diff --git a/.DS_Store b/.DS_Store index 4bca7573..6445d8c2 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.github/workflows/OTA_build.yml b/.github/workflows/OTA_build.yml new file mode 100644 index 00000000..2276440f --- /dev/null +++ b/.github/workflows/OTA_build.yml @@ -0,0 +1,97 @@ +name: OTA_Binary_building + +on: + workflow_dispatch: + +jobs: + Firmware_Buidling: + runs-on: windows-latest + steps: + # Prepare environment + - uses: actions/checkout@main + - uses: actions/cache@v3 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + - name: Install PlatformIO Core + run: pip install --upgrade platformio + + + + # Build ESP code + - name: Build PlatformIO Project ESP32 + working-directory: ./ESP32 + run: | + pio system info + pio run --environment esp32 + pio run --environment esp32s3usbotg + pio run --environment esp32-speedcrafter + pio run --environment esp32s3usbotg-gilphilbert + pio run --environment esp32s3usbotg-gilphilbert_2_0 + # copy files to dir + - name: Copy files to packing dir + run: | + copy ${{ github.workspace }}/ESP32/.pio/build/esp32/firmware.bin ${{ github.workspace }}/OTA/ControlBoard/esp32 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32/bootloader.bin ${{ github.workspace }}/OTA/ControlBoard/esp32 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32/partitions.bin ${{ github.workspace }}/OTA/ControlBoard/esp32 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg/firmware.bin ${{ github.workspace }}/OTA/ControlBoard/esp32S3 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg/bootloader.bin ${{ github.workspace }}/OTA/ControlBoard/esp32S3 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg/partitions.bin ${{ github.workspace }}/OTA/ControlBoard/esp32S3 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32-speedcrafter/firmware.bin ${{ github.workspace }}/OTA/ControlBoard/Speedcrafter + copy ${{ github.workspace }}/ESP32/.pio/build/esp32-speedcrafter/bootloader.bin ${{ github.workspace }}/OTA/ControlBoard/Speedcrafter + copy ${{ github.workspace }}/ESP32/.pio/build/esp32-speedcrafter/partitions.bin ${{ github.workspace }}/OTA/ControlBoard/Speedcrafter + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg-gilphilbert/firmware.bin ${{ github.workspace }}/OTA/ControlBoard/Gilphilbert_1_2 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg-gilphilbert/bootloader.bin ${{ github.workspace }}/OTA/ControlBoard/Gilphilbert_1_2 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg-gilphilbert/partitions.bin ${{ github.workspace }}/OTA/ControlBoard/Gilphilbert_1_2 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg-gilphilbert_2_0/firmware.bin ${{ github.workspace }}/OTA/ControlBoard/Gilphilbert_2_0 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg-gilphilbert_2_0/bootloader.bin ${{ github.workspace }}/OTA/ControlBoard/Gilphilbert_2_0 + copy ${{ github.workspace }}/ESP32/.pio/build/esp32s3usbotg-gilphilbert_2_0/partitions.bin ${{ github.workspace }}/OTA/ControlBoard/Gilphilbert_2_0 + + # Build ESP code for esp32_master + - name: Build PlatformIO Project ESP32 + working-directory: ./ESP32_master + run: | + pio system info + pio run --environment esp32s3usbotg + pio run --environment esp32 + pio run --environment esp32s3-Fanatec + pio run --environment esp32s3-gilphilbert + # copy files to dir + - name: Copy files to packing dir + run: | + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3usbotg/firmware.bin ${{ github.workspace }}/OTA/Bridge/dev_kit + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3usbotg/bootloader.bin ${{ github.workspace }}/OTA/Bridge/dev_kit + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3usbotg/partitions.bin ${{ github.workspace }}/OTA/Bridge/dev_kit + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/firmware.bin ${{ github.workspace }}/OTA/Bridge/SC_Shield + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/bootloader.bin ${{ github.workspace }}/OTA/Bridge/SC_Shield + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/partitions.bin ${{ github.workspace }}/OTA/Bridge/SC_Shield + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/firmware.bin ${{ github.workspace }}/OTA/Bridge/Fanatec_Bridge + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/bootloader.bin ${{ github.workspace }}/OTA/Bridge/Fanatec_Bridge + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/partitions.bin ${{ github.workspace }}/OTA/Bridge/Fanatec_Bridge + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-gilphilbert/firmware.bin ${{ github.workspace }}/OTA/Bridge/Gilphilbert_dongle + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-gilphilbert/bootloader.bin ${{ github.workspace }}/OTA/Bridge/Gilphilbert_dongle + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-gilphilbert/partitions.bin ${{ github.workspace }}/OTA/Bridge/Gilphilbert_dongle + + - name: Commit and push changes + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git checkout -b develop + git add OTA/ControlBoard/esp32/firmware.bin OTA/ControlBoard/esp32/partitions.bin OTA/ControlBoard/esp32/bootloader.bin + git add OTA/ControlBoard/esp32S3/firmware.bin OTA/ControlBoard/esp32S3/partitions.bin OTA/ControlBoard/esp32S3/bootloader..bin + git add OTA/ControlBoard/Speedcrafter/firmware.bin OTA/ControlBoard/Speedcrafter/partitions.bin OTA/ControlBoard/Speedcrafter/bootloader.bin + git add OTA/ControlBoard/Gilphilbert_1_2/firmware.bin OTA/ControlBoard/Gilphilbert_1_2/partitions.bin OTA/ControlBoard/Gilphilbert_1_2/bootloader.bin + git add OTA/ControlBoard/Gilphilbert_2_0/firmware.bin OTA/ControlBoard/Gilphilbert_2_0/partitions.bin OTA/ControlBoard/Gilphilbert_2_0/bootloader.bin + git add OTA/Bridge/dev_kit/firmware.bin OTA/Bridge/dev_kit/partitions.bin OTA/Bridge/dev_kit/bootloader.bin + git add OTA/Bridge/SC_Shield/firmware.bin OTA/Bridge/SC_Shield/partitions.bin OTA/Bridge/SC_Shield/bootloader.bin + git add OTA/Bridge/Fanatec_Bridge/firmware.bin OTA/Bridge/Fanatec_Bridge/partitions.bin OTA/Bridge/Fanatec_Bridge/bootloader.bin + git add OTA/Bridge/Gilphilbert_dongle/firmware.bin OTA/Bridge/Gilphilbert_dongle/partitions.bin OTA/Bridge/Gilphilbert_dongle/bootloader.bin + git commit -m "Add built firmware" + git push -u origin develop + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/PreRelease_task.yml b/.github/workflows/PreRelease_task.yml index e11a5425..1a4901d5 100644 --- a/.github/workflows/PreRelease_task.yml +++ b/.github/workflows/PreRelease_task.yml @@ -28,6 +28,29 @@ jobs: - name: output_version_date id: output_version_date run: echo "Version_date=Develop_Package_v${{ env.MY_DATE }}" >> "$GITHUB_OUTPUT" + + + + # identify version string with python script + # Set up Python (if not already set up in your workflow) + #- name: Set up Python + # uses: actions/setup-python@v4 + # with: + # python-version: '3.11' # Set the version of Python you want to use + + # Install any required dependencies for the Python script (if needed) + #- name: Install dependencies + # run: | + # pip install requests + + ## Run the Python script + #- name: Run Python Script + # run: | + # python Helper/obtainVersionString.py # Path to your Python script + + + + # create a Prerelease # see https://www.youtube.com/watch?v=_ueJ3LrRqPU - name: Create PreRelease @@ -128,6 +151,7 @@ jobs: pio system info pio run --environment esp32s3usbotg pio run --environment esp32 + pio run --environment esp32s3-Fanatec # copy files to dir - name: Copy files to packing dir run: | @@ -137,11 +161,15 @@ jobs: copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/firmware.bin ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15 copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/bootloader.bin ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15 copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/partitions.bin ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15 + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/firmware.bin ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/bootloader.bin ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/partitions.bin ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec # zip plugin binaries - name: ZIP files run: | 7z a ${{ github.workspace }}/Helper/zip/esp32s3_Bridge_With_Joy.zip ${{ github.workspace }}/Helper/bins/esp32s3_joystickreceiver/ 7z a ${{ github.workspace }}/Helper/zip/esp32_analogout_SC_D15.zip ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15/ + 7z a ${{ github.workspace }}/Helper/zip/esp32s3_Bridge_Fanatec.zip ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec/ # Build ESP code for esp32_bridge @@ -218,6 +246,17 @@ jobs: asset_name: esp32_analogout_SC_D15.zip asset_content_type: application/zip + - name: Upload ESP release assets esp32s3 bridge FANATEC + id: upload-release-asset-esp32S3_Brdige_Fanatec + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + url: ${{needs.Build-date.outputs.Upload_URL}} + with: + upload_url: ${{ env.url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./Helper/zip/esp32s3_Bridge_Fanatec.zip + asset_name: esp32s3_Bridge_Fanatec.zip + asset_content_type: application/zip ######################################################################## @@ -358,4 +397,3 @@ jobs: # asset_content_type: application/zip - diff --git a/.github/workflows/arduino.yml b/.github/workflows/arduino.yml index 18a229bf..60924701 100644 --- a/.github/workflows/arduino.yml +++ b/.github/workflows/arduino.yml @@ -128,6 +128,7 @@ jobs: pio system info pio run --environment esp32s3usbotg pio run --environment esp32 + pio run --environment esp32s3-Fanatec # copy files to dir - name: Copy files to packing dir run: | @@ -137,13 +138,16 @@ jobs: copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/firmware.bin ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15 copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/bootloader.bin ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15 copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32/partitions.bin ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15 + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/firmware.bin ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/bootloader.bin ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec + copy ${{ github.workspace }}/ESP32_master/.pio/build/esp32s3-Fanatec/partitions.bin ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec # zip plugin binaries - name: ZIP files run: | 7z a ${{ github.workspace }}/Helper/zip/esp32s3_Bridge_With_Joy.zip ${{ github.workspace }}/Helper/bins/esp32s3_joystickreceiver/ 7z a ${{ github.workspace }}/Helper/zip/esp32_analogout_SC_D15.zip ${{ github.workspace }}/Helper/bins/esp32_analogout_SC_D15/ - + 7z a ${{ github.workspace }}/Helper/zip/esp32s3_Bridge_Fanatec.zip ${{ github.workspace }}/Helper/bins/esp32s3_Bridge_Fanatec/ # upload release asset @@ -219,6 +223,17 @@ jobs: asset_name: esp32_analogout_SC_D15.zip asset_content_type: application/zip + - name: Upload ESP release assets esp32s3 bridge FANATEC + id: upload-release-asset-esp32S3_Brdige_Fanatec + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + url: ${{needs.Build-date.outputs.Upload_URL}} + with: + upload_url: ${{ env.url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./Helper/zip/esp32s3_Bridge_Fanatec.zip + asset_name: esp32s3_Bridge_Fanatec.zip + asset_content_type: application/zip ######################################################################## # Build SimHub plugin diff --git a/.github/workflows/getVersionString.yml b/.github/workflows/getVersionString.yml new file mode 100644 index 00000000..c42b12c4 --- /dev/null +++ b/.github/workflows/getVersionString.yml @@ -0,0 +1,61 @@ +# This is the name of the workflow, visible on GitHub UI. +name: Get_Python_String_Build_Task + +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ develop ] + #pull_request: + # branches: [ main ] + +# This is the list of jobs that will be run concurrently. +# Since we use a build matrix, the actual number of jobs +# started depends on how many configurations the matrix +# will produce. +jobs: + Build-date: + runs-on: ubuntu-latest + outputs: + Version_date: ${{ steps.output_version_date.outputs.Version_date }} + Upload_URL: ${{ steps.create-new-PreRelease.outputs.upload_url }} + steps: + + # Check out the repository to the GitHub Actions runner + - name: Check out repository + uses: actions/checkout@v3 + + # get date + - name: Dynamically set MY_DATE environment variable + run: echo "MY_DATE=$(date +'%Y%m%d.%H%M%S')" >> "$GITHUB_ENV" + - name: Test MY_DATE variable + run: echo ${{ env.MY_DATE }} + - name: output_version_date + id: output_version_date + run: echo "Version_date=Develop_Package_v${{ env.MY_DATE }}" >> "$GITHUB_OUTPUT" + + + + # identify version string with python script + # Set up Python (if not already set up in your workflow) + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' # Set the version of Python you want to use + + # Install any required dependencies for the Python script (if needed) + - name: Install dependencies + run: | + pip install requests + pip install regex + + # Run the Python script + - name: Run Python Script + run: | + python Helper/obtainVersionString.py # Path to your Python script + + + + + + diff --git a/.github/workflows/publishRelease.yml b/.github/workflows/publishRelease.yml deleted file mode 100644 index 34ec4b3a..00000000 --- a/.github/workflows/publishRelease.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: build_release - - -# Only trigger, when the build workflow succeeded, see https://stackoverflow.com/questions/62750603/github-actions-trigger-another-action-after-one-action-is-completed -on: - workflow_run: - workflows: - - build_firmware - - build_simhub_plugin - types: - - completed - -#on: [push] - -# This is the list of jobs that will be run concurrently. -# Since we use a build matrix, the actual number of jobs -# started depends on how many configurations the matrix -# will produce. - -# https://docs.github.com/de/actions/using-workflows/storing-workflow-data-as-artifacts - -jobs: - generateRelase: - runs-on: ubuntu-latest - steps: - - name: Download math result for job 2 - uses: actions/download-artifact@v4 - with: - name: simhub_plugin - - name: Print the final result - shell: bash - run: | - echo The result is good diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml deleted file mode 100644 index 97919782..00000000 --- a/.github/workflows/publish_release.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: build_release - - -# Only trigger, when the build workflow succeeded, see https://stackoverflow.com/questions/62750603/github-actions-trigger-another-action-after-one-action-is-completed -on: - workflow_run: - workflows: ["build_firmware","build_simhub_plugin"] - types: - - completed - - - -# This is the list of jobs that will be run concurrently. -# Since we use a build matrix, the actual number of jobs -# started depends on how many configurations the matrix -# will produce. - -# https://docs.github.com/de/actions/using-workflows/storing-workflow-data-as-artifacts - -jobs: - deploy: - name: deploy - runs-on: ubuntu-latest - steps: - - name: Download math result for job 2 - uses: actions/download-artifact@v4 - with: - name: ["simhub_plugin","firmware_esp32"] - - name: Print the final result - shell: bash - run: | - echo The result is good diff --git a/.github/workflows/simhubPlugin.yml b/.github/workflows/simhubPlugin.yml deleted file mode 100644 index 0338a3b7..00000000 --- a/.github/workflows/simhubPlugin.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: build_simhub_plugin - -on: [push] - - -# see e.g. https://cgrotz.github.io/2020-08-24-esp32_ci_cd_part2/ - -jobs: -######################################################################## -# Build SimHub plugin -######################################################################## - buildSimhubPlugin: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v2 - - name: Setup MSBuild - uses: microsoft/setup-msbuild@v1 - - - name: Setup NuGet - uses: NuGet/setup-nuget@v1.0.5 - - - name: Setup MS Build Systems - uses: microsoft/setup-msbuild@v1.1 - - - uses: actions/cache@v3 - name: Restore Caches - id: cache - with: - path: | - innounp050.rar - SimHub.8.01.2.zip - key: SimHub.8.01.2 - - - name: Download Requirements # Used to download the SimHub DLLs - only if not in cache. - if: steps.cache.outputs.cache-hit != 'true' - run: | - aria2c -j1 -o innounp050.rar "https://sourceforge.net/projects/innounp/files/innounp/innounp%200.50/innounp050.rar/download" - aria2c -j1 -o SimHub.8.01.2.zip "https://github.com/SHWotever/SimHub/releases/download/9.1.22/SimHub.9.01.22.zip" - - - name: Extract Requirements # Used to extract the SimHub DLLs - run: | - 7z x innounp050.rar - 7z x SimHub.8.01.2.zip - dir - mkdir "C:\Program Files (x86)\SimHub\" - ${{ github.workspace }}\innounp.exe -v -x -b -e -d"C:\Program Files (x86)\SimHub\" SimHubSetup_9.1.22.exe - - name: List files in dir - run: | - ls "C:\Program Files (x86)\SimHub\" - - #- name: List files in dir 2 - # run: | - # ls ${{ github.workspace }} - - name: Edit version - run: sed -i "s/\(AssemblyVersion(""\([0-9]\+\.\)\{3\}\)\([0-9]\+\)/\1${{github.run_number}}/" "SimHubPlugin/Properties/AssemblyInfo.cs" - - - name: Restore Packages - run: nuget restore "SimHubPlugin/User.PluginSdkDemo.sln" - - - name: Build solution - run: msbuild "SimHubPlugin/User.PluginSdkDemo.sln" -t:rebuild -property:Configuration=Release - - - - - - - # zip plugin binaries - - name: ZIP files - run: | - 7z a ./SimHubPlugin/bin/SimHub_plugin.zip ./SimHubPlugin/bin/* - - - - - - - - # Publish as build artifact - - name: Attach artifact - uses: actions/upload-artifact@v2 - with: - name: simhub_plugin - path: | - ./SimHubPlugin/bin/SimHub_plugin.zip \ No newline at end of file diff --git a/ESP32/.DS_Store b/ESP32/.DS_Store new file mode 100644 index 00000000..b5c98ea0 Binary files /dev/null and b/ESP32/.DS_Store differ diff --git a/ESP32/.vscode/settings.json b/ESP32/.vscode/settings.json new file mode 100644 index 00000000..444c2bf4 --- /dev/null +++ b/ESP32/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "cmath": "cpp", + "new": "cpp" + } +} \ No newline at end of file diff --git a/ESP32/include/ABSOscillation.h b/ESP32/include/ABSOscillation.h index a90d623b..44a07424 100644 --- a/ESP32/include/ABSOscillation.h +++ b/ESP32/include/ABSOscillation.h @@ -47,7 +47,7 @@ class ABSOscillation { float absAmp_fl32 = 0; switch (absForceOrTarvelBit) { case 0: - absAmp_fl32 = calcVars_st->absAmplitude; + absAmp_fl32 = calcVars_st->absAmplitude; break; case 1: absAmp_fl32 = calcVars_st->stepperPosRange * calcVars_st->absAmplitude / 100.; @@ -126,14 +126,16 @@ class RPMOscillation { //float RPM_max =10; float RPM_amp_base = calcVars_st->RPM_AMP; float RPM_amp=0; + RPM_amp=RPM_amp_base*(1.0f+0.3*RPM_value/100.0f); if(RPM_value==0) { RPM_min_freq=0; + RPM_amp=0; } - RPM_amp=RPM_amp_base*(1+0.3*RPM_value/100); + - float RPM_freq=constrain(RPM_value*(RPM_max_freq-RPM_min_freq)/100, RPM_min_freq, RPM_max_freq); + float RPM_freq=constrain(RPM_value*(RPM_max_freq-RPM_min_freq)/100.0f, RPM_min_freq, RPM_max_freq); @@ -148,7 +150,7 @@ class RPMOscillation { float RPMTimeSeconds = _RPMTimeMillis / 1000.0f; //RPMForceOffset = calcVars_st->absAmplitude * sin(calcVars_st->absFrequency * RPMTimeSeconds); - RPMForceOffset = RPM_amp * sin( 2*PI* RPM_freq* RPMTimeSeconds); + RPMForceOffset = RPM_amp * sin( 2.0f*PI* RPM_freq* RPMTimeSeconds); } _lastCallTimeMillis = timeNowMillis; @@ -444,8 +446,8 @@ class Rudder{ int32_t dead_zone_upper; int32_t dead_zone_lower; int32_t dead_zone; - int16_t sync_pedal_position; - int16_t current_pedal_position; + int32_t sync_pedal_position; + int32_t current_pedal_position; float endpos_travel; float force_range; float force_offset_raw; @@ -530,4 +532,32 @@ class Rudder{ force_offset_filter=0; } } +}; +//Rudder impact +MovingAverageFilter Averagefilter_Rudder_G_Offset(50); +class Rudder_G_Force{ + public: + int32_t offset_raw; + int32_t offset_filter; + int32_t stepper_range; + uint8_t G_value; + long stepperPosMax; + void offset_calculate(DAP_calculationVariables_st* calcVars_st) + { + stepperPosMax=(float)calcVars_st->stepperPosMax; + stepper_range=(float)calcVars_st->stepperPosRange; + float Amp_max=0.3*stepper_range; + if(calcVars_st->Rudder_status) + { + float offset= Amp_max*((float)G_value)/100.0f; + //offset=constrain(offset,0,Amp_max); + offset_filter=Averagefilter_Rudder_G_Offset.process((stepperPosMax-offset)); + } + else + { + offset_filter=calcVars_st->stepperPosMax; + } + + } + }; \ No newline at end of file diff --git a/ESP32/include/Buzzer.h b/ESP32/include/Buzzer.h new file mode 100644 index 00000000..d64a1e01 --- /dev/null +++ b/ESP32/include/Buzzer.h @@ -0,0 +1,89 @@ +#include "Pitches.h" +#include +#include +class Simple_Buzzer { +private: + int buzzer_pin; + int channel; + void noTone_buzzer() + { + ledcDetachPin(buzzer_pin); + ledcWrite(channel, 0); + } + void tone_buzzer(uint16_t frequency, uint16_t duration, uint8_t volume)// should add notone_buzzer after that + { + ledcSetup(channel, frequency, 12); + ledcAttachPin(buzzer_pin, channel); + ledcWrite(channel, volume); + if (duration) { + delay(duration); + //noTone_buzzer(); + } + } +public: + void single_beep_tone(int sound_Hz, int duration) + { + tone(buzzer_pin, sound_Hz, duration); + // to distinguish the notes, set a minimum time between them. + // the note's duration + 30% seems to work well: + delay(duration); + // stop the tone playing: + noTone(buzzer_pin); + } + void play_melody_tone(int* melody, int melody_size, double* noteDurations) + { + // iterate over the notes of the melody: + for (int thisNote = 0; thisNote < melody_size; thisNote++) { + // to calculate the note duration, take one second divided by the note type. + //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. + double noteDuration = 1000 / noteDurations[thisNote]; + tone(buzzer_pin, melody[thisNote], noteDuration); + // to distinguish the notes, set a minimum time between them. + // the note's duration + 30% seems to work well: + double pauseBetweenNotes = noteDuration * 1.3; + delay(pauseBetweenNotes); + // stop the tone playing: + noTone(buzzer_pin); + } + } + void initialized(int pin, int _channel) + { + buzzer_pin=pin; + channel = _channel; + ledcSetup(channel, 6000, 8); + ledcAttachPin(buzzer_pin, channel); + } + + + + void single_beep_ledc_fade(int sound_Hz, int duration, double cycle) + { + int step_quantity=80; + int duration_steps = (duration/step_quantity); + uint32_t volume=0; + int volume_step=255/step_quantity; + for(int i=0;i // define the payload revision -#define DAP_VERSION_CONFIG 141 +#define DAP_VERSION_CONFIG 142 // define the payload types #define DAP_PAYLOAD_TYPE_CONFIG 100 @@ -188,7 +188,7 @@ struct payloadPedalConfig { //OTA flag //uint8_t OTA_flag; - uint8_t enableReboot_u8; + uint8_t stepLossFunctionFlags_u8; //joystick out flag //uint8_t Joystick_ESPsync_to_ESP; @@ -280,13 +280,15 @@ struct DAP_calculationVariables_st float WS_freq; bool Rudder_status; uint8_t pedal_type; - uint16_t sync_pedal_position; - uint16_t current_pedal_position; + uint32_t sync_pedal_position; + uint32_t current_pedal_position; float current_pedal_position_ratio; float Sync_pedal_position_ratio; bool rudder_brake_status; long stepperPosMin_default; + long stepperPosMax_default; float stepperPosRange_default; + uint32_t stepsPerMotorRevolution; void updateFromConfig(DAP_config_st& config_st); void updateEndstops(long newMinEndstop, long newMaxEndstop); @@ -295,5 +297,6 @@ struct DAP_calculationVariables_st void reset_maxforce(); void StepperPos_setback(); void Default_pos(); - void update_stepperpos(long newMinstop); + void update_stepperMinpos(long newMinstop); + void update_stepperMaxpos(long newMaxstop); }; diff --git a/ESP32/include/ESPNOW_lib.h b/ESP32/include/ESPNOW_lib.h index d3ea72c9..87c15a38 100644 --- a/ESP32/include/ESPNOW_lib.h +++ b/ESP32/include/ESPNOW_lib.h @@ -28,9 +28,9 @@ bool ESPNow_Pairing_status = false; bool UpdatePairingToEeprom = false; bool ESPNow_pairing_action_b = false; bool software_pairing_action_b = false; - - - +bool hardware_pairing_action_b = false; +bool OTA_update_action_b=false; +bool Config_update_b=false; struct ESPNow_Send_Struct { uint16_t pedal_position; @@ -219,7 +219,8 @@ void onRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) if (structChecker == true) { //Serial.println("Updating pedal config"); - configUpdateAvailable = true; + configUpdateAvailable = true; + Config_update_b=true; } xSemaphoreGive(semaphore_updateConfig); } @@ -260,11 +261,7 @@ void onRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) if (structChecker == true) { - //1=trigger reset pedal position - if (dap_actions_st.payloadPedalAction_.system_action_u8==1) - { - resetPedalPosition = true; - } + //2= restart pedal if (dap_actions_st.payloadPedalAction_.system_action_u8==2) { @@ -289,8 +286,15 @@ void onRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) { _WSOscillation.trigger(); } - //Road impact - _Road_impact_effect.Road_Impact_value=dap_actions_st.payloadPedalAction_.impact_value_u8; + //Road impact && Rudder G impact + if(dap_calculationVariables_st.Rudder_status==false) + { + _Road_impact_effect.Road_Impact_value=dap_actions_st.payloadPedalAction_.impact_value_u8; + } + else + { + _rudder_g_force.G_value=dap_actions_st.payloadPedalAction_.impact_value_u8; + } // trigger system identification if (dap_actions_st.payloadPedalAction_.startSystemIdentification_u8) { @@ -364,6 +368,13 @@ void onRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) } + if(data_len==sizeof(Basic_WIfi_info)) + { + memcpy(&_basic_wifi_info, data, sizeof(Basic_WIfi_info)); + OTA_update_action_b=true; + } + + } diff --git a/ESP32/include/Main.h b/ESP32/include/Main.h index 065b1255..489ef92f 100644 --- a/ESP32/include/Main.h +++ b/ESP32/include/Main.h @@ -1,6 +1,9 @@ #pragma once //#include + +//#define PRINT_TASK_FREE_STACKSIZE_IN_WORDS + /********************************************************************/ /* Select the PCB */ /********************************************************************/ @@ -22,8 +25,6 @@ // target cycle time for pedal update task, to get constant cycle times, required for FIR filtering #define DAP_MICROSECONDS_PER_SECOND 1000000 -static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; - // 15kHz //#define ADC_SAMPLE_RATE ADS1256_DRATE_15000SPS //#define PUT_TARGET_CYCLE_TIME_IN_US DAP_MICROSECONDS_PER_SECOND / 15000 @@ -37,12 +38,12 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; //#define PUT_TARGET_CYCLE_TIME_IN_US DAP_MICROSECONDS_PER_SECOND / 3750 // 2.0kHz -//#define ADC_SAMPLE_RATE ADS1256_DRATE_2000SPS -//#define PUT_TARGET_CYCLE_TIME_IN_US DAP_MICROSECONDS_PER_SECOND / 2000 +#define ADC_SAMPLE_RATE ADS1256_DRATE_2000SPS +#define PUT_TARGET_CYCLE_TIME_IN_US DAP_MICROSECONDS_PER_SECOND / 2000 // 1.0kHz -#define ADC_SAMPLE_RATE ADS1256_DRATE_1000SPS -#define PUT_TARGET_CYCLE_TIME_IN_US DAP_MICROSECONDS_PER_SECOND / 1000 +//#define ADC_SAMPLE_RATE ADS1256_DRATE_1000SPS +//#define PUT_TARGET_CYCLE_TIME_IN_US DAP_MICROSECONDS_PER_SECOND / 1000 @@ -58,8 +59,9 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; /* Motor defines */ /********************************************************************/ //#define MOTOR_INVERT_MOTOR_DIR false - - +static const uint32_t MAXIMUM_STEPPER_RPM = 4000; +static const uint32_t SECONDS_PER_MINUTE = 60; +#define MAXIMUM_STEPPER_SPEED (uint32_t)250000// max steps per second, see https://github.com/gin66/FastAccelStepper /********************************************************************/ @@ -79,9 +81,6 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; #define dirPinStepper 0 #define stepPinStepper 4 - // endstop pins - #define minPin 34 - #define maxPin 35 // level shifter not present on this PCB design #define SENSORLESS_HOMING false @@ -106,9 +105,6 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; #define dirPinStepper 8 #define stepPinStepper 9 - // endstop pins - #define minPin 11 - #define maxPin 10 // level shifter not present on this PCB design #define SENSORLESS_HOMING false @@ -138,10 +134,6 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; //I2Cpins #define I2C_SDA 32 #define I2C_SCL 33 - - // endstop pins - #define minPin 12 - #define maxPin 13 // level shifter is present on this PCB design #define SENSORLESS_HOMING true @@ -151,7 +143,7 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; #define PEDAL_ASSIGNMENT #define CFG1 15 #define CFG2 12 - #define Using_analog_output + //#define Using_analog_output //#define Using_I2C_Sync #define ESPNOW_Enable #define ESPNow_ESP32 @@ -159,8 +151,12 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; #define BLUETOOTH_GAMEPAD //#define USB_JOYSTICK #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 1 - #define ESPNow_Pairing_function - #define Pairing_GPIO 0 + //#define ESPNow_Pairing_function + //#define Pairing_GPIO 13 + //#define ESPNow_debug_rudder + #define OTA_update_ESP32 + #define BRAKE_RESISTOR_PIN 13 + #endif @@ -178,10 +174,6 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; // stepper pins #define dirPinStepper 32 #define stepPinStepper 33 - - // endstop pins - #define minPin 35 - #define maxPin 34 // level shifter is present on this PCB design #define SENSORLESS_HOMING true @@ -192,8 +184,9 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; //#define USB_JOYSTICK #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 3 - #define Pairing_GPIO 0 - #define ESPNow_Pairing_function + //#define Pairing_GPIO 0 + //#define ESPNow_Pairing_function + #define ESPNow_ESP32 #endif @@ -212,10 +205,6 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; // stepper pins #define dirPinStepper 22 #define stepPinStepper 23 - - // endstop pins - #define minPin 35 - #define maxPin 34 // level shifter is present on this PCB design #define SENSORLESS_HOMING true @@ -226,7 +215,9 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; //#define USB_JOYSTICK #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 3 #define Pairing_GPIO 0 - #define ESPNow_Pairing_function + //#define ESPNow_Pairing_function + #define ESPNow_ESP32 + #define OTA_update_ESP32 #endif @@ -254,25 +245,22 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; //MCP4725 SDA SCL #define MCP_SDA 48 #define MCP_SCL 47 - - // endstop pins - #define minPin 12 - #define maxPin 13 // level shifter is present on this PCB design #define SENSORLESS_HOMING true #define ISV57_TXPIN 10//27 //17 #define ISV57_RXPIN 9//26 // 16 - #define Using_analog_output_ESP32_S3 + //#define Using_analog_output_ESP32_S3 //#define BLUETOOTH_GAMEPAD #define USB_JOYSTICK #define ESPNOW_Enable #define ESPNow_S3 #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 - #define ESPNow_Pairing_function + //#define ESPNow_Pairing_function #define Pairing_GPIO 0 + #define OTA_update #endif // For Gilphilbert PCBA design @@ -296,10 +284,7 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; //MCP4725 SDA SCL #define MCP_SDA 5 #define MCP_SCL 4 - - // endstop pins - #define minPin 12 - #define maxPin 13 + // Pedal assignment pin #define PEDAL_ASSIGNMENT #define CFG1 1 @@ -319,43 +304,46 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; #define USB_JOYSTICK #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 - #define ESPNow_Pairing_function + //#define ESPNow_Pairing_function + //#define Hardware_Pairing_button #define Pairing_GPIO 0 + //#define ESPNow_debug_rudder + #define USING_LED + #define LED_GPIO 12 + #define OTA_update + #define USING_BUZZER #endif #if PCB_VERSION == 8 // ADC defines - #define PIN_DRDY 4//19// 19 --> DRDY + #define PIN_DRDY 15//19// 19 --> DRDY #define PIN_RST 6 // X --> X - #define PIN_SCK 1//16 // 16 -->SCLK - #define PIN_MISO 3 // 18 --> DOUT - #define PIN_MOSI 2 // 17 --> DIN - #define PIN_CS 5//21 // 21 --> CS + #define PIN_SCK 16//16 // 16 -->SCLK + #define PIN_MISO 18 // 18 --> DOUT + #define PIN_MOSI 17 // 17 --> DIN + #define PIN_CS 7//21 // 21 --> CS // stepper pins - #define dirPinStepper 6//22 - #define stepPinStepper 7//23 + #define dirPinStepper 37//22 + #define stepPinStepper 38//23 //analog output pin //#define D_O 25 //MCP4725 SDA SCL - //#define MCP_SDA 5 - //#define MCP_SCL 4 - - // endstop pins - #define minPin 8 - #define maxPin 9 + #define MCP_SDA 5 + #define MCP_SCL 4 + // Pedal assignment pin #define PEDAL_ASSIGNMENT - #define CFG1 10 - #define CFG2 11 + #define CFG1 1 + #define CFG2 2 - //#define EMERGENCY_BUTTON - //#define ShutdownPin 6 + #define EMERGENCY_BUTTON + #define ShutdownPin 6 // level shifter is present on this PCB design #define SENSORLESS_HOMING true - #define ISV57_TXPIN 12//27 //17 - #define ISV57_RXPIN 13//26 // 16 + #define ISV57_TXPIN 10//27 //17 + #define ISV57_RXPIN 9//26 // 16 //#define Using_analog_output_ESP32_S3 #define ESPNOW_Enable @@ -364,4 +352,93 @@ static const uint32_t STEPS_PER_MOTOR_REVOLUTION = 6400; #define USB_JOYSTICK #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 + //#define ESPNow_Pairing_function + //#define Hardware_Pairing_button + #define Pairing_GPIO 33 + //#define ESPNow_debug_rudder + #define CONTROLLER_SPECIFIC_VIDPID + #define USING_LED + #define LED_GPIO 12 + #define OTA_update + #define USING_BUZZER +#endif + +// V3 version of dev PCB for inverted serial, dev only +#if PCB_VERSION == 9 + // ADC defines + #define PIN_DRDY 19// 19 --> DRDY + #define PIN_RST 15 // X --> X + #define PIN_SCK 16 // 16 -->SCLK + #define PIN_MISO 18 // 18 --> DOUT + #define PIN_MOSI 17 // 17 --> DIN + #define PIN_CS 21 // 21 --> CS + + // stepper pins + #define dirPinStepper 22 + #define stepPinStepper 23 + //analog output pin + #define D_O 25 + //I2Cpins + #define I2C_SDA 32 + #define I2C_SCL 33 + + // level shifter is present on this PCB design + #define SENSORLESS_HOMING true + #define ISV57_TXPIN 27 //17 + #define ISV57_RXPIN 26 // 16 + //pedal assignment + #define PEDAL_ASSIGNMENT + #define CFG1 15 + #define CFG2 12 + //#define Using_analog_output + //#define Using_I2C_Sync + #define ESPNOW_Enable + #define ESPNow_ESP32 + #define I2C_slave_address 0x15 + #define BLUETOOTH_GAMEPAD + //#define USB_JOYSTICK + #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 1 + //#define ESPNow_Pairing_function + //#define Pairing_GPIO 13 + //#define ESPNow_debug_rudder + #define OTA_update_ESP32 + + #endif + +// V4 version of dev PCB for inverted serial, dev only +#if PCB_VERSION == 10 + // ADC defines + #define PIN_DRDY 15//19// 19 --> DRDY + #define PIN_RST 6 // X --> X + #define PIN_SCK 16//16 // 16 -->SCLK + #define PIN_MISO 18 // 18 --> DOUT + #define PIN_MOSI 17 // 17 --> DIN + #define PIN_CS 7//21 // 21 --> CS + + // stepper pins + #define dirPinStepper 37//22 + #define stepPinStepper 38//23 + + //analog output pin + //#define D_O 25 + //MCP4725 SDA SCL + #define MCP_SDA 48 + #define MCP_SCL 47 + + // level shifter is present on this PCB design + #define SENSORLESS_HOMING true + #define ISV57_TXPIN 10//27 //17 + #define ISV57_RXPIN 9//26 // 16 + + //#define Using_analog_output_ESP32_S3 + + //#define BLUETOOTH_GAMEPAD + #define USB_JOYSTICK + #define ESPNOW_Enable + #define ESPNow_S3 + #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 + //#define ESPNow_Pairing_function + #define Pairing_GPIO 0 + #define OTA_update +#endif \ No newline at end of file diff --git a/ESP32/include/Modbus.h b/ESP32/include/Modbus.h index eaa07bdf..bdf6151b 100644 --- a/ESP32/include/Modbus.h +++ b/ESP32/include/Modbus.h @@ -16,7 +16,7 @@ class Modbus /* data */ bool log = false; int mode_ = -1; - uint32_t timeout_ = 20; + uint32_t timeout_ = 100; HardwareSerial* s ; uint8_t rawRx[512]; int lenRx = 0; diff --git a/ESP32/include/OTA_Pull.h b/ESP32/include/OTA_Pull.h new file mode 100644 index 00000000..9b559e12 --- /dev/null +++ b/ESP32/include/OTA_Pull.h @@ -0,0 +1,118 @@ +#include +#include +#include +#define JSON_URL_dev "https://raw.githubusercontent.com/gilphilbert/pedal-flasher/main/json/dev/Version_ControlBoard.json" +//#define JSON_URL_dev "https://raw.githubusercontent.com/tcfshcrw/playground/main/OTA_test_repo/GH2/Version.json" +#define JSON_URL_main "https://raw.githubusercontent.com/gilphilbert/pedal-flasher/main/json/main/Version_ControlBoard.json" +bool OTA_enable_b =false; +bool OTA_status =false; +struct Basic_WIfi_info +{ + uint8_t payloadType; + uint8_t device_ID; + uint8_t wifi_action; + uint8_t mode_select; + uint8_t SSID_Length; + uint8_t PASS_Length; + uint8_t WIFI_SSID[30]; + uint8_t WIFI_PASS[30]; +}; + +Basic_WIfi_info _basic_wifi_info; +char* SSID; +char* PASS; + +void wifi_initialized(char* Wifi_SSID, char* Wifi_PASS) +{ + Serial.print("SSID: "); + Serial.print(Wifi_SSID); + Serial.print(" PASS: "); + Serial.println(Wifi_PASS); + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + delay(100); + //esp_wifi_set_max_tx_power(WIFI_POWER_8_5dBm); + WiFi.begin(Wifi_SSID, Wifi_PASS); + + // Display connection progress + Serial.print("Connecting to WiFi:"); + Serial.print(WiFi.SSID()); + Serial.print(" "); + // Wait until WiFi is connected + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + // Print confirmation message when WiFi is connected + Serial.println("WiFi connected"); + Serial.print("WiFi RSSI: "); + Serial.println(WiFi.RSSI()); + +} +void OTAcallback(int offset, int totallength); + +const char *errtext(int code) +{ + switch(code) + { + case ESP32OTAPull::UPDATE_AVAILABLE: + return "An update is available but wasn't installed"; + case ESP32OTAPull::NO_UPDATE_PROFILE_FOUND: + return "No profile matches"; + case ESP32OTAPull::NO_UPDATE_AVAILABLE: + return "Profile matched, but update not applicable"; + case ESP32OTAPull::UPDATE_OK: + return "An update was done, but no reboot"; + case ESP32OTAPull::HTTP_FAILED: + return "HTTP GET failure"; + case ESP32OTAPull::WRITE_ERROR: + return "Write error"; + case ESP32OTAPull::JSON_PROBLEM: + return "Invalid JSON"; + case ESP32OTAPull::OTA_UPDATE_FAIL: + return "Update fail (no OTA partition?)"; + default: + if (code > 0) + return "Unexpected HTTP response code"; + break; + } + return "Unknown error"; +} +/* +void DisplayInfo() +{ + char exampleImageURL[256]; + snprintf(exampleImageURL, sizeof(exampleImageURL), "https://example.com/Basic-OTA-Example-%s-%s.bin", ARDUINO_BOARD, VERSION); + + Serial.printf("Basic-OTA-Example v%s\n", VERSION); + Serial.printf("You need to post a JSON (text) file similar to this:\n"); + Serial.printf("{\n"); + Serial.printf(" \"Configurations\": [\n"); + Serial.printf(" {\n"); + Serial.printf(" \"Board\": \"%s\",\n", ARDUINO_BOARD); + Serial.printf(" \"Device\": \"%s\",\n", WiFi.macAddress().c_str()); + Serial.printf(" \"Version\": \"%s\",\n", VERSION); + Serial.printf(" \"URL\": \"%s\"\n", exampleImageURL); + Serial.printf(" }\n"); + Serial.printf(" ]\n"); + Serial.printf("}\n"); + Serial.printf("\n"); + Serial.printf("(Board, Device, Config, and Version are all *optional*.)\n"); + Serial.printf("\n"); + Serial.printf("Post the JSON at, e.g., %s\n", JSON_URL_main); + Serial.printf("Post the compiled bin at, e.g., %s\n\n", exampleImageURL); +} +*/ + +void OTAcallback(int offset, int totallength) +{ + Serial.print("Updating: "); + Serial.print(offset); + Serial.print(" of "); + Serial.print(totallength); + Serial.print("("); + Serial.print(100 * offset / totallength); + Serial.println("%)"); + +} \ No newline at end of file diff --git a/ESP32/include/PedalGeometry.h b/ESP32/include/PedalGeometry.h index c5ab5100..e7601654 100644 --- a/ESP32/include/PedalGeometry.h +++ b/ESP32/include/PedalGeometry.h @@ -3,15 +3,13 @@ #include "DiyActivePedal_types.h" #include -static const float TRAVEL_PER_ROTATION_IN_MM = 5.0; // determined by lead screw pitch & starts - - class StepperWithLimits; -float sledPositionInMM(StepperWithLimits* stepper, DAP_config_st& config_st); -float pedalInclineAngleDeg(float sledPositionMM, DAP_config_st& config_st); +float sledPositionInMM(StepperWithLimits* stepper, DAP_config_st * config_st, float motorRevolutionsPerStep_fl32); +float sledPositionInMM_withPositionAsArgument(float currentPos_fl32, DAP_config_st * config_st, float motorRevolutionsPerStep_fl32); +float pedalInclineAngleDeg(float sledPositionMM, DAP_config_st * config_st); float pedalInclineAngleAccel(float pedalInclineAngleDeg_global); -float convertToPedalForce(float F_l, float sledPositionMM, DAP_config_st& config_st); -float convertToPedalForceGain(float sledPositionMM, DAP_config_st& config_st); +float convertToPedalForce(float F_l, float sledPositionMM, DAP_config_st * config_st); +float convertToPedalForceGain(float sledPositionMM, DAP_config_st * config_st); diff --git a/ESP32/include/Pitches.h b/ESP32/include/Pitches.h new file mode 100644 index 00000000..5ea8ad87 --- /dev/null +++ b/ESP32/include/Pitches.h @@ -0,0 +1,98 @@ +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 + +int melody_victory_theme[] = { + NOTE_D4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_AS3, NOTE_C4, NOTE_D4, 0, NOTE_C4, NOTE_D4 +}; + +// note durations: 4 = quarter note, 8 = eighth note, etD.: +double melody_durations_Victory_theme[] = { + 12, 12, 12, 4, 4, 4, 12, 12, 12, 2 +}; \ No newline at end of file diff --git a/ESP32/include/StepperMovementStrategy.h b/ESP32/include/StepperMovementStrategy.h index 9d4ddf0d..a330e6ea 100644 --- a/ESP32/include/StepperMovementStrategy.h +++ b/ESP32/include/StepperMovementStrategy.h @@ -4,9 +4,6 @@ #include "Main.h" - - - // see https://github.com/Dlloydev/QuickPID/blob/master/examples/PID_Basic/PID_Basic.ino #include @@ -220,20 +217,44 @@ int32_t MoveByForceTargetingStrategy(float loadCellReadingKg, StepperWithLimits* */ // get current stepper position - float stepperPos = stepper->getCurrentPosition(); + float stepperPos = stepper->getCurrentPositionFromMin(); // add velocity feedforward - stepperPos += changeVelocity * config_st->payLoadPedalConfig_.PID_velocity_feedforward_gain; + //stepperPos += changeVelocity * config_st->payLoadPedalConfig_.PID_velocity_feedforward_gain; // motion corrected loadcell reading float loadCellReadingKg_corrected = loadCellReadingKg; - //loadCellReadingKg_corrected += config_st->payLoadPedalConfig_.MPC_1st_order_gain * stepper_vel_filtered_fl32 / STEPS_PER_MOTOR_REVOLUTION / 10;// + stepper_accel_filtered_fl32; - //loadCellReadingKg_corrected += config_st->payLoadPedalConfig_.MPC_1st_order_gain * stepper_accel_filtered_fl32 / STEPS_PER_MOTOR_REVOLUTION / 10;// + stepper_accel_filtered_fl32; - // set initial guess float stepperPos_initial = stepperPos; + // foot spring stiffness + float d_f_d_phi = -config_st->payLoadPedalConfig_.MPC_0th_order_gain; + + // how many mm movement to order if 1kg of error force is detected + // this can be tuned for responsiveness vs oscillation + float mm_per_motor_rev = config_st->payLoadPedalConfig_.spindlePitch_mmPerRev_u8;//TRAVEL_PER_ROTATION_IN_MM; + float steps_per_motor_rev = (float)calc_st->stepsPerMotorRevolution; //(float)STEPS_PER_MOTOR_REVOLUTION; + + float move_mm_per_kg = config_st->payLoadPedalConfig_.MPC_0th_order_gain; + float MOVE_STEPS_FOR_1KG = (move_mm_per_kg / mm_per_motor_rev) * steps_per_motor_rev; + + float mmPerStep = 0; + if (steps_per_motor_rev > 0) + { + mmPerStep = mm_per_motor_rev / steps_per_motor_rev ; + } + + + // Serial.printf("PosFraction: %f\n", stepper->getCurrentPositionFractionFromExternalPos( stepperPos )); + // Serial.printf("PosMin: %d\n", stepper->getMinPosition()); + // delay(20); + + // Serial.printf("PosFraction:%f, TargetForce: %f, LoadcellForce:%f\n", stepper->getCurrentPositionFractionFromExternalPos( stepperPos ), forceCurve->EvalForceCubicSpline(config_st, calc_st, stepper->getCurrentPositionFractionFromExternalPos( stepperPos )), loadCellReadingKg_corrected); + // delay(20); + + + // Find the intersections of the force curve and the foot model via Newtons-method #define MAX_NUMBER_OF_NEWTON_STEPS 5 for (uint8_t iterationIdx = 0; iterationIdx < MAX_NUMBER_OF_NEWTON_STEPS; iterationIdx++) @@ -248,34 +269,24 @@ int32_t MoveByForceTargetingStrategy(float loadCellReadingKg, StepperWithLimits* float loadCellTargetKg = forceCurve->EvalForceCubicSpline(config_st, calc_st, x_0); float gradient_force_curve_fl32 = forceCurve->EvalForceGradientCubicSpline(config_st, calc_st, x_0, false); - // apply effect force offset - loadCellTargetKg -= absForceOffset_fl32; - - // how many mm movement to order if 1kg of error force is detected - // this can be tuned for responsiveness vs oscillation - float mm_per_motor_rev = config_st->payLoadPedalConfig_.spindlePitch_mmPerRev_u8;//TRAVEL_PER_ROTATION_IN_MM; - float steps_per_motor_rev = (float)STEPS_PER_MOTOR_REVOLUTION; + // Convert loadcell reading to pedal force + // float sledPosition = sledPositionInMM_withPositionAsArgument(x_0 * stepper->getTravelSteps(), config_st, motorRevolutionsPerSteps_fl32); + // float pedalInclineAngleInDeg_fl32 = pedalInclineAngleDeg(sledPosition, config_st); + // // float pedalForce_fl32 = convertToPedalForce(loadcellReading, sledPosition, &dap_config_pedalUpdateTask_st); + // float d_phi_d_x_2 = convertToPedalForceGain(sledPosition, config_st); - // foot spring stiffness - float d_f_d_phi = -config_st->payLoadPedalConfig_.MPC_0th_order_gain; - - float move_mm_per_kg = config_st->payLoadPedalConfig_.MPC_0th_order_gain; - float MOVE_STEPS_FOR_1KG = (move_mm_per_kg / mm_per_motor_rev) * steps_per_motor_rev; - + // // compute gain for horizontal foot model + // float b = config_st->payLoadPedalConfig_.lengthPedal_b; + // float d = config_st->payLoadPedalConfig_.lengthPedal_d; + // float d_x_hor_d_phi_2 = -(b+d) * sinf(pedalInclineAngleInDeg_fl32 * DEG_TO_RAD_FL32); + // apply effect force offset + loadCellTargetKg -= absForceOffset_fl32; // make stiffness dependent on force curve gradient // less steps per kg --> steeper line float gradient_normalized_force_curve_fl32 = forceCurve->EvalForceGradientCubicSpline(config_st, calc_st, x_0, true); - gradient_normalized_force_curve_fl32 = constrain(gradient_normalized_force_curve_fl32, 0.05, 1); - - float mmPerStep = 0; - if (steps_per_motor_rev > 0) - { - mmPerStep = mm_per_motor_rev / steps_per_motor_rev ; - } - - + gradient_normalized_force_curve_fl32 = constrain(gradient_normalized_force_curve_fl32, 0.05f, 1.0f); // The foot is modeled to be of proportional resistance with respect to deflection. Since the deflection depends on the pedal kinematics, the kinematic must be respected here // This is accomplished with the forceGain variable @@ -295,6 +306,7 @@ int32_t MoveByForceTargetingStrategy(float loadCellReadingKg, StepperWithLimits* // Translational foot model // given in kg/step float m1 = d_f_d_phi * (-d_x_hor_d_phi) * (-d_phi_d_x) * mmPerStep; + // float m1 = d_f_d_phi * mmPerStep; // smoothen gradient with force curve gradient since it had better results w/ clutch pedal characteristic //m1 /= gradient_normalized_force_curve_fl32; @@ -315,7 +327,10 @@ int32_t MoveByForceTargetingStrategy(float loadCellReadingKg, StepperWithLimits* stepperPos -= stepUpdate; } } - + + // readd the min position + stepperPos += stepper->getMinPosition(); + // limit the position update float deltaMax = 0.5 * (float)(calc_st->stepperPosMax - calc_st->stepperPosMin); int32_t posStepperNew = constrain(stepperPos, stepperPos_initial-deltaMax, stepperPos_initial+deltaMax ); @@ -327,38 +342,38 @@ int32_t MoveByForceTargetingStrategy(float loadCellReadingKg, StepperWithLimits* } -int32_t mpcBasedMove(float loadCellReadingKg, float stepperPosFraction, StepperWithLimits* stepper, ForceCurve_Interpolated* forceCurve, const DAP_calculationVariables_st* calc_st, DAP_config_st* config_st, float absForceOffset_fl32) -{ +// int32_t mpcBasedMove(float loadCellReadingKg, float stepperPosFraction, StepperWithLimits* stepper, ForceCurve_Interpolated* forceCurve, const DAP_calculationVariables_st* calc_st, DAP_config_st* config_st, float absForceOffset_fl32) +// { - static const float MOVE_MM_FOR_1KG = 3.0; - static const float MOVE_STEPS_FOR_1KG = (MOVE_MM_FOR_1KG / TRAVEL_PER_ROTATION_IN_MM) * STEPS_PER_MOTOR_REVOLUTION; +// static const float MOVE_MM_FOR_1KG = 3.0; +// static const float MOVE_STEPS_FOR_1KG = (MOVE_MM_FOR_1KG / TRAVEL_PER_ROTATION_IN_MM) * STEPS_PER_MOTOR_REVOLUTION; - // get target force at current location - float loadCellTargetKg = forceCurve->EvalForceCubicSpline(config_st, calc_st, stepperPosFraction); - loadCellTargetKg -=absForceOffset_fl32; +// // get target force at current location +// float loadCellTargetKg = forceCurve->EvalForceCubicSpline(config_st, calc_st, stepperPosFraction); +// loadCellTargetKg -=absForceOffset_fl32; - // get loadcell reading - float loadCellReadingKg_clip = constrain(loadCellReadingKg, calc_st->Force_Min, calc_st->Force_Max); +// // get loadcell reading +// float loadCellReadingKg_clip = constrain(loadCellReadingKg, calc_st->Force_Min, calc_st->Force_Max); - // if target force at location is lower than loadcell reading --> move towards the foot k_f * n_steps +// // if target force at location is lower than loadcell reading --> move towards the foot k_f * n_steps - // Take into account system constraints like stepper rpm & acceleration +// // Take into account system constraints like stepper rpm & acceleration - // if target force at location is lower than loadcell reading --> move away from the foot -k_f * n_steps +// // if target force at location is lower than loadcell reading --> move away from the foot -k_f * n_steps - // predict target force at new location and compare to predicted force --> compute cost matrix +// // predict target force at new location and compare to predicted force --> compute cost matrix @@ -367,60 +382,60 @@ int32_t mpcBasedMove(float loadCellReadingKg, float stepperPosFraction, StepperW - // e_k = r^2 = (F_lc - k * (delta_x_0) - F_t(x_0 + delta_x_0))^2 +// // e_k = r^2 = (F_lc - k * (delta_x_0) - F_t(x_0 + delta_x_0))^2 - // r: force residue +// // r: force residue - // e: cost +// // e: cost - // F_lc: current loadcell measurement +// // F_lc: current loadcell measurement - // k: sping stiffness of the foot +// // k: sping stiffness of the foot - // x_0: current stepper position +// // x_0: current stepper position - // x_1: next stepper pos +// // x_1: next stepper pos - // delta_x_0 = x_1 - x_0: step update at time step 0 +// // delta_x_0 = x_1 - x_0: step update at time step 0 - // F_t(x): target force at location +// // F_t(x): target force at location - // minimize e with x_1 +// // minimize e with x_1 - // d[e(delta_x_0)] / d[delta_x_0] == 0 +// // d[e(delta_x_0)] / d[delta_x_0] == 0 - // d[e] / d[delta_x_0] = d[e] / d[r] * d[r] / d[delta_x_0] +// // d[e] / d[delta_x_0] = d[e] / d[r] * d[r] / d[delta_x_0] - // d[e] / d[r] = 2 * r +// // d[e] / d[r] = 2 * r - // d[r] / d[delta_x_0] = d[F_lc - k * (delta_x_0) - F_t(x_0 + delta_x_0)] = -k - d[F_t]/d[delta_x_0] +// // d[r] / d[delta_x_0] = d[F_lc - k * (delta_x_0) - F_t(x_0 + delta_x_0)] = -k - d[F_t]/d[delta_x_0] - // MPC: sum up over planing horizon and optimize costs +// // MPC: sum up over planing horizon and optimize costs - // take only the first control value & repeat in the next cycle +// // take only the first control value & repeat in the next cycle - // constraint |delta_x_0| < max step rate +// // constraint |delta_x_0| < max step rate - // l = sum_k( e_k(delta_x_k, x_0) ) +// // l = sum_k( e_k(delta_x_k, x_0) ) - // where k = [0, 1, ..., N] +// // where k = [0, 1, ..., N] - -} +// return 0; +// } @@ -479,10 +494,10 @@ void measureStepResponse(StepperWithLimits* stepper, const DAP_calculationVariab loadcellReading = (loadcellReading - calc_st->Force_Min) / calc_st->Force_Range; static RTDebugOutput rtDebugFilter; - rtDebugFilter.offerData({ ((float)t) *1e-6 , currentPos, loadcellReading}); + rtDebugFilter.offerData({ ((float)t) *1e-6f , currentPos, loadcellReading}); } } Serial.println("======================================"); Serial.println("End system identification data"); -} +} \ No newline at end of file diff --git a/ESP32/include/StepperWithLimits.h b/ESP32/include/StepperWithLimits.h index 7be2061a..8fcdb720 100644 --- a/ESP32/include/StepperWithLimits.h +++ b/ESP32/include/StepperWithLimits.h @@ -4,48 +4,96 @@ #include "Main.h" // these are physical properties of the stepper -static const uint32_t MAXIMUM_STEPPER_RPM = 4000; -static const uint32_t SECONDS_PER_MINUTE = 60; -//static const uint32_t MAXIMUM_STEPPER_SPEED = ( (float)MAXIMUM_STEPPER_RPM * (float)STEPS_PER_MOTOR_REVOLUTION) / (float)SECONDS_PER_MINUTE; // steps/s -#define MAXIMUM_STEPPER_SPEED (uint32_t)300000// max steps per second, see https://github.com/gin66/FastAccelStepper -static const int32_t MAXIMUM_STEPPER_ACCELERATION = 1e10; // steps/s² +static const int32_t MAXIMUM_STEPPER_ACCELERATION = INT32_MAX; // steps/s² class StepperWithLimits { private: - FastAccelStepper* _stepper; - uint8_t _pinMin, _pinMax; // pins that limit switches attach to - int32_t _limitMin, _limitMax; // stepper position at limit switches - int32_t _posMin, _posMax; // stepper position at min/max of travel + FastAccelStepper* _stepper; + int32_t _endstopLimitMin, _endstopLimitMax; // stepper position at limit switches + int32_t _posMin, _posMax; // stepper position at min/max of travel -public: - StepperWithLimits(uint8_t pinStep, uint8_t pinDirection, uint8_t pinMin, uint8_t pinMax, bool invertMotorDir_b); - bool hasValidStepper() const { return NULL != _stepper; } + isv57communication isv57; + -public: - void findMinMaxEndstops(); - void refindMinLimit(); - void checkLimitsAndResetIfNecessary(); - void updatePedalMinMaxPos(uint8_t pedalStartPosPct, uint8_t pedalEndPosPct); - bool isAtMinPos(); - bool correctPos(int32_t posOffset); - void findMinMaxSensorless(isv57communication * isv57, DAP_config_st dap_config_st); - void refindMinLimitSensorless(isv57communication * isv57); -public: - int8_t moveTo(int32_t position, bool blocking = false); - void moveSlowlyToPos(int32_t targetPos_ui32); - void printStates(); + /*public: void StartTask(void) + { + //Start Task with input parameter set to "this" class + xTaskCreatePinnedToCore( + this->servoCommunicationTask, //Function to implement the task + "servoCommunicationTask", //Name of the task + 5000, //Stack size in words + this, //Task input parameter + 1, //Priority of the task + &task_iSV_Communication, //Task handle. + 0); //Core where the task should run + }*/ -public: - int32_t getCurrentPositionFromMin() const; - int32_t getCurrentPosition() const; - double getCurrentPositionFraction() const; - double getCurrentPositionFractionFromExternalPos(int32_t extPos_i32) const; - int32_t getTargetPositionSteps() const; + + + + + bool isv57LifeSignal_b = false; + bool invertMotorDir_global_b = false; + int32_t servoPos_i16 = 0; + int32_t servo_offset_compensation_steps_i32 = 0; + + bool restartServo = false; + void setLifelineSignal(); + + bool enableSteplossRecov_b = true; + bool enableCrashDetection_b = true; + + bool logAllServoParams = false; + + int32_t servoPos_local_corrected_i32 = 0; + + uint32_t stepsPerMotorRev_u32 = 3200u; + + public: - int32_t getLimitMin() const { return _limitMin; } - int32_t getLimitMax() const { return _limitMax; } - int32_t getTravelSteps() const { return _posMax - _posMin; } - void setSpeed(uint32_t speedInStepsPerSecond); + StepperWithLimits(uint8_t pinStep, uint8_t pinDirection, bool invertMotorDir_b, uint32_t stepsPerMotorRev_arg_u32); + bool hasValidStepper() const { return NULL != _stepper; } + + void checkLimitsAndResetIfNecessary(); + void updatePedalMinMaxPos(uint8_t pedalStartPosPct, uint8_t pedalEndPosPct); + bool isAtMinPos(); + void correctPos(); + void findMinMaxSensorless(DAP_config_st dap_config_st); + void forceStop(); + int8_t moveTo(int32_t position, bool blocking = false); + void moveSlowlyToPos(int32_t targetPos_ui32); + + int32_t getCurrentPositionFromMin() const; + int32_t getMinPosition() const; + void setMinPosition(); + int32_t getCurrentPosition() const; + float getCurrentPositionFraction() const; + float getCurrentPositionFractionFromExternalPos(int32_t extPos_i32) const; + int32_t getTargetPositionSteps() const; + + int32_t getLimitMin() const { return _endstopLimitMin; } + int32_t getLimitMax() const { return _endstopLimitMax; } + int32_t getTravelSteps() const { return _posMax - _posMin; } + void setSpeed(uint32_t speedInStepsPerSecond); + + int32_t getPositionDeviation(); + int32_t getServosInternalPosition(); + //int32_t getStepLossCompensation(); + int32_t getServosVoltage(); + int32_t getServosCurrent(); + int32_t getServosPos(); + bool getLifelineSignal(); + + void configSteplossRecovAndCrashDetection(uint8_t flags_u8); + void printAllServoParameters(); + + + void setServosInternalPositionCorrected(int32_t posCorrected_i32); + int32_t getServosInternalPositionCorrected(); + + + static void servoCommunicationTask( void * pvParameters ); + }; diff --git a/ESP32/include/Version_Board.h b/ESP32/include/Version_Board.h new file mode 100644 index 00000000..6d88cbd1 --- /dev/null +++ b/ESP32/include/Version_Board.h @@ -0,0 +1,26 @@ +#define DAP_FIRMWARE_VERSION "0.87.99" +#if PCB_VERSION==3 + #define CONTROL_BOARD "V3_ESP32" +#endif + +#if PCB_VERSION==5 + #define CONTROL_BOARD "Speedcrafter" +#endif + +#if PCB_VERSION==6 + #define CONTROL_BOARD "V4_ESP32S3" +#endif + +#if PCB_VERSION==7 + #define CONTROL_BOARD "Gilphilbert_PCBAv1" +#endif + +#if PCB_VERSION==8 + #define CONTROL_BOARD "Gilphilbert_PCBAv2" +#endif +#if PCB_VERSION==9 + #define CONTROL_BOARD "V3_ESP32" +#endif +#if PCB_VERSION==10 + #define CONTROL_BOARD "V4_ESP32S3" +#endif \ No newline at end of file diff --git a/ESP32/include/isv57communication.h b/ESP32/include/isv57communication.h index 3d5b8f67..ad6e858d 100644 --- a/ESP32/include/isv57communication.h +++ b/ESP32/include/isv57communication.h @@ -53,7 +53,7 @@ class isv57communication { public: isv57communication(); void setupServoStateReading(); - void sendTunedServoParameters(); + void sendTunedServoParameters(bool commandRotationDirection, uint32_t stepsPerMotorRev_u32); void readAllServoParameters(); void readServoStates(); bool checkCommunication(); @@ -61,12 +61,18 @@ class isv57communication { bool clearServoAlarms(); bool readAlarmHistory(); bool readCurrentAlarm(); - + void resetToFactoryParams(); + + void clearServoUnitPosition(); + void disableAxis(); + void enableAxis(); + //void resetAxisCounter(); void setZeroPos(); void applyOfsetToZeroPos(int16_t givenPosOffset_i16); int16_t getZeroPos(); + int16_t getPosFromMin(); int16_t regArray[4]; int16_t slaveId = 63; diff --git a/ESP32/src/ota.h b/ESP32/include/ota.h similarity index 99% rename from ESP32/src/ota.h rename to ESP32/include/ota.h index a3cb0626..a5cafc77 100644 --- a/ESP32/src/ota.h +++ b/ESP32/include/ota.h @@ -7,6 +7,19 @@ #include //#include #include +struct Basic_WIfi_info +{ + uint8_t payloadType; + uint8_t device_ID; + uint8_t wifi_action; + uint8_t mode_select; + uint8_t SSID_Length; + uint8_t PASS_Length; + uint8_t WIFI_SSID[30]; + uint8_t WIFI_PASS[30]; +}; + +Basic_WIfi_info _basic_wifi_info; diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index 1fd677bb..0aabbd3a 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -9,7 +9,6 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = esp32 [env] framework = arduino @@ -22,17 +21,20 @@ monitor_speed = 921600 [common] lib_deps_external = rfetick/Kalman @ ^1.1.0 - lemmingdev/ESP32-BLE-Gamepad @ ^0.5.5 #gin66/FastAccelStepper @ ^0.30.12 - gin66/FastAccelStepper @ ^0.31.0 + gin66/FastAccelStepper @ ^0.31.3 dlloydev/QuickPID @ ^3.1.9 tomstewart89/BasicLinearAlgebra @ ^3.2 https://github.com/ChrGri/ADS1255-ADS1256.git + #https://github.com/ChrGri/FastNonAccelStepper.git + #https://github.com/RobTillaart/FastTrig.git + [env:esp32s3usbotg] board = esp32-s3-devkitc-1 board_build.f_cpu = 240000000L build_flags = + -O3 # compiler optimization for runtime -DARDUINO_RUNNING_CORE=1 -DCORE_DEBUG_LEVEL=1 -DARDUINO_USB_MODE=0 @@ -52,15 +54,23 @@ lib_deps = schnoog/Joystick_ESP32S2 @ ^0.9.4 adafruit/Adafruit MCP4725 @ ^2.0.2 regenbogencode/ESPNowW@^1.0.2 + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 + [env:esp32] board = esp32dev lib_deps = ${common.lib_deps_external} regenbogencode/ESPNowW@^1.0.2 + #lemmingdev/ESP32-BLE-Gamepad @^0.5.3 + ESP32-BLE-Gamepad=https://github.com/lemmingDev/ESP32-BLE-Gamepad/archive/refs/tags/v0.5.4.zip + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 build_unflags = '-D PCB_VERSION=6' build_flags = + -O3 # compiler optimization for runtime '-D PCB_VERSION=3' [env:esp32-speedcrafter] @@ -68,15 +78,19 @@ board = esp-wrover-kit lib_deps = ${common.lib_deps_external} regenbogencode/ESPNowW@^1.0.2 + #lemmingdev/ESP32-BLE-Gamepad @^0.5.3 + ESP32-BLE-Gamepad=https://github.com/lemmingDev/ESP32-BLE-Gamepad/archive/refs/tags/v0.5.4.zip build_unflags = '-D PCB_VERSION=6' build_flags = + -O3 # compiler optimization for runtime '-D PCB_VERSION=5' [env:esp32s3usbotg-gilphilbert] board = esp32-s3-devkitc-1 board_build.f_cpu = 240000000L build_flags = + -O3 # compiler optimization for runtime -DARDUINO_RUNNING_CORE=1 -DCORE_DEBUG_LEVEL=1 -DARDUINO_USB_MODE=0 @@ -95,19 +109,53 @@ lib_deps = ${common.lib_deps_external} schnoog/Joystick_ESP32S2 @ ^0.9.4 adafruit/Adafruit MCP4725 @ ^2.0.2 + regenbogencode/ESPNowW@^1.0.2 + adafruit/Adafruit NeoPixel@^1.12.3 + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 +[env:esp32s3usbotg-gilphilbert_2_0] +board = lolin_s3_mini +board_build.f_cpu = 240000000L +build_unflags = + -DARDUINO_USB_CDC_ON_BOOT=1 +build_flags = + -O3 # compiler optimization for runtime + -DARDUINO_RUNNING_CORE=1 + -DCORE_DEBUG_LEVEL=0 + -DARDUINO_USB_MODE=0 + -DARDUINO_USB_CDC_ON_BOOT=0 + -DARDUINO_USB_MSC_ON_BOOT=0 + -DARDUINO_USB_DFU_ON_BOOT=0 + -DPCB_VERSION=8 + '-DUSB_VID=0xF011' + '-DUSB_PID=0xF011' + '-DUSB_PRODUCT="DiyFfbPedal"' + '-DUSB_MANUFACTURER="OpenSource"' +board_upload.use_1200bps_touch = yes +board_upload.wait_for_upload_port = yes +board_upload.require_upload_port = yes +lib_deps = + ${common.lib_deps_external} + Joystick_ESP32S2=https://github.com/schnoog/Joystick_ESP32S2/archive/refs/heads/dev.zip + adafruit/Adafruit MCP4725 @ ^2.0.2 regenbogencode/ESPNowW@^1.0.2 + adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit NeoPixel@^1.12.3 + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 -[env:esp32s3usbotg-4R2P] -board = adafruit_feather_esp32s3 +[env:esp32s3-V4-non-inverted-serial] +board = esp32-s3-devkitc-1 board_build.f_cpu = 240000000L build_flags = + -O3 # compiler optimization for runtime -DARDUINO_RUNNING_CORE=1 -DCORE_DEBUG_LEVEL=1 -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 - -DPCB_VERSION=8 + -DPCB_VERSION=10 -DUSB_VID=0xF011 -DUSB_PID=0xF011 '-DUSB_PRODUCT="DiyFfbPedal"' @@ -119,4 +167,22 @@ lib_deps = ${common.lib_deps_external} schnoog/Joystick_ESP32S2 @ ^0.9.4 adafruit/Adafruit MCP4725 @ ^2.0.2 - regenbogencode/ESPNowW@^1.0.2 \ No newline at end of file + regenbogencode/ESPNowW@^1.0.2 + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 + + +[env:esp32-V3-non-inverted-serial] +board = esp32dev +lib_deps = + ${common.lib_deps_external} + regenbogencode/ESPNowW@^1.0.2 + #lemmingdev/ESP32-BLE-Gamepad @^0.5.3 + ESP32-BLE-Gamepad=https://github.com/lemmingDev/ESP32-BLE-Gamepad/archive/refs/tags/v0.5.4.zip + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 +build_unflags = + '-D PCB_VERSION=6' +build_flags = + -O3 # compiler optimization for runtime + -DPCB_VERSION=9 diff --git a/ESP32/src/.DS_Store b/ESP32/src/.DS_Store index c6179262..edd9412e 100644 Binary files a/ESP32/src/.DS_Store and b/ESP32/src/.DS_Store differ diff --git a/ESP32/src/.theia/launch.json b/ESP32/src/.theia/launch.json deleted file mode 100644 index a2ea02c4..00000000 --- a/ESP32/src/.theia/launch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - "version": "0.2.0", - "configurations": [] -} diff --git a/ESP32/src/Controller.cpp b/ESP32/src/Controller.cpp index 0028c3aa..65335393 100644 --- a/ESP32/src/Controller.cpp +++ b/ESP32/src/Controller.cpp @@ -28,6 +28,39 @@ //USB.begin(); } + void SetupController_USB(uint8_t pedal_ID) + { + int PID; + char *APname; + switch(pedal_ID) + { + case 0: + PID=0x8214; + APname="FFB_Pedal_Clutch"; + break; + case 1: + PID=0x8215; + APname="FFB_Pedal_Brake"; + break; + case 2: + PID=0x8216; + APname="FFB_Pedal_Throttle"; + break; + default: + PID=0x8217; + APname="FFB_Pedal_NOASSIGNMENT"; + break; + + } + USB.PID(PID); + USB.VID(0x3035); + USB.productName(APname); + USB.manufacturerName("OpenSource"); + USB.begin(); + Joystick.setBrakeRange(JOYSTICK_MIN_VALUE, JOYSTICK_MAX_VALUE); + delay(100); + Joystick.begin(); + } bool IsControllerReady() { return true; } void SetControllerOutputValue(int32_t value) { Joystick.setBrake(value); diff --git a/ESP32/src/DiyActivePedal_types.cpp b/ESP32/src/DiyActivePedal_types.cpp index c16b1872..52eeb6fb 100644 --- a/ESP32/src/DiyActivePedal_types.cpp +++ b/ESP32/src/DiyActivePedal_types.cpp @@ -99,7 +99,7 @@ void DAP_config_st::initialiseDefaults() { payLoadPedalConfig_.invertMotorDirection_u8 = 0; payLoadPedalConfig_.pedal_type=4; //payLoadPedalConfig_.OTA_flag=0; - payLoadPedalConfig_.enableReboot_u8=1; + payLoadPedalConfig_.stepLossFunctionFlags_u8=0b11; //payLoadPedalConfig_.Joystick_ESPsync_to_ESP=0; } @@ -183,6 +183,18 @@ void DAP_calculationVariables_st::updateFromConfig(DAP_config_st& config_st) { Force_Range = Force_Max - Force_Min; Force_Max_default=((float)config_st.payLoadPedalConfig_.maxForce); pedal_type=config_st.payLoadPedalConfig_.pedal_type; + + // calculate steps per motor revolution + // float helper = MAXIMUM_STEPPER_SPEED / (MAXIMUM_STEPPER_RPM / SECONDS_PER_MINUTE); + // helper = floor(helper / 10) * 10; + // helper = constrain(helper, 2000, 10000); + // stepsPerMotorRevolution = helper; + + // when spindle pitch is smaller than 8, choose coarse microstepping + if ( 8 > config_st.payLoadPedalConfig_.spindlePitch_mmPerRev_u8) + {stepsPerMotorRevolution = 3200;} + else{stepsPerMotorRevolution = 6400;} + } void DAP_calculationVariables_st::dynamic_update() @@ -210,6 +222,7 @@ void DAP_calculationVariables_st::updateEndstops(long newMinEndstop, long newMax stepperPosMax = stepperPosEndstopRange * endPosRel; stepperPosMin_default = stepperPosMin; stepperPosRange = stepperPosMax - stepperPosMin; + //current_pedal_position_ratio=((float)(current_pedal_position-stepperPosMin_default))/((float)stepperPosRange_default); } void DAP_calculationVariables_st::updateStiffness() { @@ -228,18 +241,27 @@ void DAP_calculationVariables_st::updateStiffness() { void DAP_calculationVariables_st::StepperPos_setback() { stepperPosMin=stepperPosMin_default; + stepperPosMax=stepperPosMax_default; stepperPosRange = stepperPosRange_default; } -void DAP_calculationVariables_st::update_stepperpos(long newMinstop) +void DAP_calculationVariables_st::update_stepperMinpos(long newMinstop) { stepperPosMin=newMinstop; + + stepperPosRange = stepperPosMax - stepperPosMin; +} +void DAP_calculationVariables_st::update_stepperMaxpos( long newMaxstop) +{ + + stepperPosMax=newMaxstop; stepperPosRange = stepperPosMax - stepperPosMin; } void DAP_calculationVariables_st::Default_pos() { stepperPosMin_default = stepperPosMin; + stepperPosMax_default = stepperPosMax; stepperPosRange_default=stepperPosRange; } diff --git a/ESP32/src/ForceCurve.cpp b/ESP32/src/ForceCurve.cpp index bca92f08..602343fe 100644 --- a/ESP32/src/ForceCurve.cpp +++ b/ESP32/src/ForceCurve.cpp @@ -33,9 +33,9 @@ float ForceCurve_Interpolated::EvalForceCubicSpline(const DAP_config_st* config_ yOrig[5] = config_st->payLoadPedalConfig_.relativeForce_p100; //double dx = 1.0f; - double t = (splineSegment_fl32 - (float)splineSegment_u8);// / dx; - double y = (1 - t) * yOrig[splineSegment_u8] + t * yOrig[splineSegment_u8 + 1] + t * (1 - t) * (a * (1 - t) + b * t); - + float t = (splineSegment_fl32 - (float)splineSegment_u8);// / dx; + float y = (1 - t) * yOrig[splineSegment_u8] + t * yOrig[splineSegment_u8 + 1] + t * (1 - t) * (a * (1 - t) + b * t); + if (calc_st->Force_Range> 0) { y = calc_st->Force_Min + y / 100.0f * calc_st->Force_Range; @@ -79,11 +79,11 @@ float ForceCurve_Interpolated::EvalForceGradientCubicSpline(const DAP_config_st* - double Delta_x_orig = 100; // total horizontal range [0,100] - double dx = Delta_x_orig / NUMBER_OF_SPLINE_SEGMENTS; // spline segment horizontal range - double t = (splineSegment_fl32 - (float)splineSegment_u8); // relative position in spline segment [0, 1] - double dy = yOrig[splineSegment_u8 + 1] - yOrig[splineSegment_u8]; // spline segment vertical range - double y_prime = 0; + float Delta_x_orig = 100; // total horizontal range [0,100] + float dx = Delta_x_orig / NUMBER_OF_SPLINE_SEGMENTS; // spline segment horizontal range + float t = (splineSegment_fl32 - (float)splineSegment_u8); // relative position in spline segment [0, 1] + float dy = yOrig[splineSegment_u8 + 1] - yOrig[splineSegment_u8]; // spline segment vertical range + float y_prime = 0; if (fabs(dx) > 0) { y_prime = dy / dx + (1 - 2 * t) * (a * (1 - t) + b * t) / dx + t * (1 - t) * (b - a) / dx; @@ -92,8 +92,8 @@ float ForceCurve_Interpolated::EvalForceGradientCubicSpline(const DAP_config_st* // --> conversion of the gradient to the proper axis scaling is performed if (normalized_b == false) { - double d_y_scale = calc_st->Force_Range / 100.0; - double d_x_scale=0; + float d_y_scale = calc_st->Force_Range / 100.0; + float d_x_scale=0; if (fabs(calc_st->stepperPosRange) > 0.01) { d_x_scale = 100.0 / calc_st->stepperPosRange; diff --git a/ESP32/src/LoadCell.cpp b/ESP32/src/LoadCell.cpp index a2540368..2990dcad 100644 --- a/ESP32/src/LoadCell.cpp +++ b/ESP32/src/LoadCell.cpp @@ -55,12 +55,12 @@ ADS1256& ADC() { void LoadCell_ADS1256::setLoadcellRating(uint8_t loadcellRating_u8) const { ADS1256& adc = ADC(); - double originalConversionFactor_f64 = CONVERSION_FACTOR; + float originalConversionFactor_f64 = CONVERSION_FACTOR; - double updatedConversionFactor_f64 = 1; + float updatedConversionFactor_f64 = 1; if (LOADCELL_WEIGHT_RATING_KG>0) { - updatedConversionFactor_f64 = 2 * ((double)loadcellRating_u8) * (CONVERSION_FACTOR/LOADCELL_WEIGHT_RATING_KG); + updatedConversionFactor_f64 = 2 * ((float)loadcellRating_u8) * (CONVERSION_FACTOR/LOADCELL_WEIGHT_RATING_KG); } Serial.print("OrigConversionFactor: "); Serial.print(originalConversionFactor_f64); diff --git a/ESP32/src/Main.cpp b/ESP32/src/Main.cpp index 7f90e268..f1242a43 100644 --- a/ESP32/src/Main.cpp +++ b/ESP32/src/Main.cpp @@ -3,7 +3,6 @@ // https://github.com/espressif/arduino-esp32/issues/7779 #define ESTIMATE_LOADCELL_VARIANCE -#define ISV_COMMUNICATION //#define PRINT_SERVO_STATES #define DEBUG_INFO_0_CYCLE_TIMER 1 @@ -13,24 +12,19 @@ #define DEBUG_INFO_0_PRINT_ALL_SERVO_REGISTERS 16 #define DEBUG_INFO_0_STATE_BASIC_INFO_STRUCT 32 #define DEBUG_INFO_0_STATE_EXTENDED_INFO_STRUCT 64 -#define DEBUG_INFO_0_CONTROL_LOOP_ALGO 128 - -bool resetServoEncoder = true; -bool isv57LifeSignal_b = false; -bool isv57_not_live_b=false; -#ifdef ISV_COMMUNICATION - #include "isv57communication.h" - int32_t servo_offset_compensation_steps_i32 = 0; -#endif +#define DEBUG_INFO_0_LOG_ALL_SERVO_PARAMS 128 + + +#define SERVO_VOLTAGE_TO_STOP_MOVEMENT_IN_0p1V 400 + -#define OTA_update -#define PI 3.14159267 -#define DEG_TO_RAD PI / 180 +//#define PI 3.14159267 +#define DEG_TO_RAD_FL32 0.017453292519943295769236907684886f #include "Arduino.h" #include "Main.h" - +#include "Version_Board.h" #ifdef Using_analog_output_ESP32_S3 #include #include @@ -56,6 +50,7 @@ void serialCommunicationTask( void * pvParameters ); void servoCommunicationTask( void * pvParameters ); void OTATask( void * pvParameters ); void ESPNOW_SyncTask( void * pvParameters); +#define INCLUDE_vTaskDelete 1 // https://www.tutorialspoint.com/cyclic-redundancy-check-crc-in-arduino uint16_t checksumCalculator(uint8_t * data, uint16_t length) { @@ -74,7 +69,6 @@ uint16_t checksumCalculator(uint8_t * data, uint16_t length) bool systemIdentificationMode_b = false; -int16_t servoPos_i16 = 0; @@ -96,6 +90,7 @@ Road_impact_effect _Road_impact_effect; Custom_vibration CV1; Custom_vibration CV2; Rudder _rudder; +Rudder_G_Force _rudder_g_force; #define ABS_OSCILLATION @@ -145,11 +140,6 @@ ForceCurve_Interpolated forceCurve; TaskHandle_t Task1; TaskHandle_t Task2; -#ifdef ISV_COMMUNICATION - isv57communication isv57; - #define STACK_SIZE_FOR_TASK_3 0.2 * (configTOTAL_HEAP_SIZE / 4) - TaskHandle_t Task3; -#endif static SemaphoreHandle_t semaphore_updateConfig=NULL; bool configUpdateAvailable = false; // semaphore protected data @@ -158,10 +148,7 @@ static SemaphoreHandle_t semaphore_updateConfig=NULL; static SemaphoreHandle_t semaphore_updateJoystick=NULL; int32_t joystickNormalizedToInt32 = 0; // semaphore protected data -static SemaphoreHandle_t semaphore_resetServoPos=NULL; -bool resetPedalPosition = false; -static SemaphoreHandle_t semaphore_readServoValues=NULL; static SemaphoreHandle_t semaphore_updatePedalStates=NULL; @@ -192,6 +179,7 @@ static SemaphoreHandle_t semaphore_updatePedalStates=NULL; /**********************************************************************************************/ #include "PedalGeometry.h" +float motorRevolutionsPerSteps_fl32 = 1.0f / 3200.0f; /**********************************************************************************************/ @@ -241,10 +229,17 @@ bool moveSlowlyToPosition_b = false; /**********************************************************************************************/ //OTA update #ifdef OTA_update -#include "ota.h" +//#include "ota.h" +#include "OTA_Pull.h" TaskHandle_t Task4; char* APhost; #endif +#ifdef OTA_update_ESP32 + #include "ota.h" + //#include "OTA_Pull.h" + TaskHandle_t Task4; + char* APhost; +#endif //ESPNOW @@ -253,6 +248,29 @@ char* APhost; TaskHandle_t Task6; #endif +#ifdef USING_LED + #include "soc/soc_caps.h" + #include + #define LEDS_COUNT 1 + Adafruit_NeoPixel pixels(LEDS_COUNT, LED_GPIO, NEO_GRB + NEO_KHZ800); + #define CHANNEL 0 + #define LED_BRIGHT 30 + /* + static const crgb_t L_RED = 0xff0000; + static const crgb_t L_GREEN = 0x00ff00; + static const crgb_t L_BLUE = 0x0000ff; + static const crgb_t L_WHITE = 0xe0e0e0; + static const crgb_t L_YELLOW = 0xffde21; + static const crgb_t L_ORANGE = 0xffa500; + static const crgb_t L_CYAN = 0x00ffff; + static const crgb_t L_PURPLE = 0x800080; + */ +#endif + +#ifdef USING_BUZZER + #include "Buzzer.h" +#endif + /**********************************************************************************************/ @@ -262,14 +280,34 @@ char* APhost; /**********************************************************************************************/ void setup() { + +// setup brake resistor pin +#ifdef BRAKE_RESISTOR_PIN + pinMode(BRAKE_RESISTOR_PIN, OUTPUT); // Set GPIO13 as an output + digitalWrite(BRAKE_RESISTOR_PIN, LOW); // Turn the LED on +#endif + + + //Serial.begin(115200); //Serial.begin(921600); //Serial.begin(512000); // + #ifdef USING_LED + pixels.begin(); + pixels.setBrightness(20); + pixels.setPixelColor(0,0xff,0xff,0xff); + pixels.show(); + #endif + #ifdef USING_BUZZER + Buzzer.initialized(ShutdownPin,1); + Buzzer.single_beep_tone(770,100); + #endif - #if PCB_VERSION == 6 + #if PCB_VERSION == 6 || PCB_VERSION == 7 Serial.setTxTimeoutMs(0); + Serial.begin(921600); #else Serial.begin(921600); Serial.setTimeout(5); @@ -277,58 +315,33 @@ void setup() Serial.println(" "); Serial.println(" "); Serial.println(" "); - - // init controller - SetupController(); - delay(3000); + #ifndef CONTROLLER_SPECIFIC_VIDPID + // init controller + SetupController(); + //delay(3000); + #endif + //delay(3000); Serial.println("This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License."); Serial.println("Please check github repo for more detail: https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal"); //printout the github releasing version - + //#ifdef OTA_update + Serial.print("Board: "); + Serial.println(CONTROL_BOARD); + Serial.print("Firmware Version:"); + Serial.println(DAP_FIRMWARE_VERSION); + //#endif -// check whether iSV57 communication can be established -// and in case, (a) send tuned servo parameters and (b) prepare the servo for signal read -#ifdef ISV_COMMUNICATION - - bool isv57slaveIdFound_b = isv57.findServosSlaveId(); - Serial.print("iSV57 slaveId found: "); - Serial.println( isv57slaveIdFound_b ); - - if (!isv57slaveIdFound_b) - { - Serial.println( "Restarting ESP" ); - ESP.restart(); - } - - - // check whether iSV57 is connected - isv57LifeSignal_b = isv57.checkCommunication(); - if (!isv57LifeSignal_b) - { - Serial.println( "Restarting ESP" ); - ESP.restart(); - } - - // read servos alarm history - isv57.readAlarmHistory(); - - // reset iSV57 alarms - bool servoAlarmsCleared = isv57.clearServoAlarms(); - delay(500); - - Serial.print("iSV57 communication state: "); - Serial.println(isv57LifeSignal_b); - - if (isv57LifeSignal_b) - { - isv57.setupServoStateReading(); - isv57.sendTunedServoParameters(); - } - delay(200); -#endif -pinMode(Pairing_GPIO, INPUT_PULLUP); + #ifdef Hardware_Pairing_button + pinMode(Pairing_GPIO, INPUT_PULLUP); + #endif + #ifdef USING_LED + pixels.begin(); + pixels.setBrightness(20); + pixels.setPixelColor(0,0xff,0x00,0x00); + pixels.show(); + #endif // initialize configuration and update local variables dap_config_st.initialiseDefaults(); @@ -401,11 +414,20 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); // interprete config values dap_calculationVariables_st.updateFromConfig(dap_config_st); - + #ifdef USING_LED + //pixels.setBrightness(20); + pixels.setPixelColor(0,0x5f,0x5f,0x00);//yellow + pixels.show(); + //delay(3000); + #endif bool invMotorDir = dap_config_st.payLoadPedalConfig_.invertMotorDirection_u8 > 0; - stepper = new StepperWithLimits(stepPinStepper, dirPinStepper, minPin, maxPin, invMotorDir); + stepper = new StepperWithLimits(stepPinStepper, dirPinStepper, invMotorDir, dap_calculationVariables_st.stepsPerMotorRevolution); + + motorRevolutionsPerSteps_fl32 = 1.0f / ( (float)dap_calculationVariables_st.stepsPerMotorRevolution ); + Serial.printf("Steps per motor revolution: %d\n", dap_calculationVariables_st.stepsPerMotorRevolution); + loadcell = new LoadCell_ADS1256(); loadcell->setLoadcellRating(dap_config_st.payLoadPedalConfig_.loadcell_rating); @@ -415,17 +437,9 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); loadcell->estimateVariance(); // automatically identify sensor noise for KF parameterization #endif - // find the min & max endstops - Serial.print("Start homing"); - if (isv57LifeSignal_b && SENSORLESS_HOMING) - { - - stepper->findMinMaxSensorless(&isv57, dap_config_st); - } - else - { - stepper->findMinMaxEndstops(); - } + // find the min & max endstops + Serial.println("Start homing"); + stepper->findMinMaxSensorless(dap_config_st); Serial.print("Min Position is "); Serial.println(stepper->getLimitMin()); @@ -438,7 +452,12 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); kalman = new KalmanFilter(loadcell->getVarianceEstimate()); kalman_2nd_order = new KalmanFilter_2nd_order(1); - + #ifdef USING_LED + //pixels.setBrightness(20); + pixels.setPixelColor(0, 0x80, 0x00, 0x80);//purple + pixels.show(); + //delay(3000); + #endif @@ -463,7 +482,6 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); // setup multi tasking semaphore_updateJoystick = xSemaphoreCreateMutex(); semaphore_updateConfig = xSemaphoreCreateMutex(); - semaphore_resetServoPos = xSemaphoreCreateMutex(); semaphore_updatePedalStates = xSemaphoreCreateMutex(); delay(10); @@ -480,26 +498,15 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); } - - // print all servo registers - if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_PRINT_ALL_SERVO_REGISTERS) - { - if (isv57LifeSignal_b) - { - isv57.readAllServoParameters(); - } - } - - - - disableCore0WDT(); + Serial.println("Starting other tasks"); + //create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1 xTaskCreatePinnedToCore( pedalUpdateTask, /* Task function. */ "pedalUpdateTask", /* name of task. */ - 10000, /* Stack size of task */ + 7000, /* Stack size of task */ //STACK_SIZE_FOR_TASK_1, NULL, /* parameter of the task */ 1, /* priority of the task */ @@ -510,7 +517,7 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); xTaskCreatePinnedToCore( serialCommunicationTask, "serialCommunicationTask", - 10000, + 5000, //STACK_SIZE_FOR_TASK_2, NULL, 1, @@ -518,24 +525,11 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); 0); delay(500); - #ifdef ISV_COMMUNICATION - - xTaskCreatePinnedToCore( - servoCommunicationTask, - "servoCommunicationTask", - 10000, - //STACK_SIZE_FOR_TASK_2, - NULL, - 1, - &Task3, - 0); - delay(500); -#endif //Serial.begin(115200); - #ifdef OTA_update + #if defined(OTA_update) || defined(OTA_update_ESP32) switch(dap_config_st.payLoadPedalConfig_.pedal_type) { @@ -552,8 +546,8 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); APhost="FFBPedal"; break; - } - + } + //Serial.begin(115200); xTaskCreatePinnedToCore( OTATask, "OTATask", @@ -564,7 +558,6 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); &Task4, 0); delay(500); - #endif //MCP setup @@ -607,6 +600,14 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); //MCP.begin(); } #endif + + #ifdef USING_LED + //pixels.setBrightness(20); + pixels.setPixelColor(0,0x00,0x00,0xff);//Blue + pixels.show(); + //delay(3000); + #endif + #ifdef PEDAL_ASSIGNMENT pinMode(CFG1, INPUT_PULLUP); pinMode(CFG2, INPUT_PULLUP); @@ -657,6 +658,7 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); #ifdef ESPNOW_Enable dap_calculationVariables_st.rudder_brake_status=false; + Serial.println("Starting ESP now tasks"); if(dap_config_st.payLoadPedalConfig_.pedal_type==0||dap_config_st.payLoadPedalConfig_.pedal_type==1||dap_config_st.payLoadPedalConfig_.pedal_type==2) { ESPNow_initialize(); @@ -671,16 +673,39 @@ pinMode(Pairing_GPIO, INPUT_PULLUP); 0); delay(500); } - - - - - - + #endif + #ifdef CONTROLLER_SPECIFIC_VIDPID + SetupController_USB(dap_config_st.payLoadPedalConfig_.pedal_type); + delay(500); #endif Serial.println("Setup end"); - + #ifdef USING_LED + //pixels.setBrightness(20); + pixels.setPixelColor(0,0x00,0xff,0x00);//Green + pixels.show(); + //delay(3000); + #endif + + #ifdef USING_BUZZER + if(dap_config_st.payLoadPedalConfig_.pedal_type==0) + { + delay(500); + Buzzer.single_beep_ledc_fade(NOTE_D4,3072,1); + //Buzzer.single_beep_ledc_fade(NOTE_A4,1536,0.5); + } + if(dap_config_st.payLoadPedalConfig_.pedal_type==1) + { + Buzzer.single_beep_ledc_fade(NOTE_A4,3072,1); + } + if(dap_config_st.payLoadPedalConfig_.pedal_type==2) + { + delay(500); + //Buzzer.single_beep_ledc_fade(NOTE_A4,1536,0.5); + Buzzer.single_beep_ledc_fade(NOTE_D4,3072,1); + } + //Buzzer.single_beep_tone(440,1500); + #endif } @@ -748,8 +773,16 @@ uint printCntr = 0; int64_t timeNow_pedalUpdateTask_l = 0; int64_t timePrevious_pedalUpdateTask_l = 0; -#define REPETITION_INTERVAL_PEDALUPDATE_TASK (int64_t)1 +#define REPETITION_INTERVAL_PEDALUPDATE_TASK (int64_t)0 + +uint32_t pos_printCount = 0; + +uint32_t controlTask_stackSizeIdx_u32 = 0; +float Position_Next_Prev = 0.0f; + +//IRAM_ATTR DAP_config_st dap_config_pedalUpdateTask_st; +DAP_config_st dap_config_pedalUpdateTask_st; //void loop() void pedalUpdateTask( void * pvParameters ) { @@ -765,16 +798,6 @@ void pedalUpdateTask( void * pvParameters ) timePrevious_pedalUpdateTask_l = millis(); - // system identification mode - #ifdef ALLOW_SYSTEM_IDENTIFICATION - if (systemIdentificationMode_b == true) - { - measureStepResponse(stepper, &dap_calculationVariables_st, &dap_config_st, loadcell); - systemIdentificationMode_b = false; - } - #endif - - // controll cycle time. Delay did not work with the multi tasking, thus this workaround was integrated unsigned long now = micros(); if (now - cycleTimeLastCall < PUT_TARGET_CYCLE_TIME_IN_US) // 100us = 10kHz @@ -787,15 +810,31 @@ void pedalUpdateTask( void * pvParameters ) cycleTimeLastCall = now; } - - // print the execution time averaged over multiple cycles if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_CYCLE_TIMER) { static CycleTimer timerPU("PU cycle time"); timerPU.Bump(); } - + + + + + // system identification mode + #ifdef ALLOW_SYSTEM_IDENTIFICATION + if (systemIdentificationMode_b == true) + { + measureStepResponse(stepper, &dap_calculationVariables_st, &dap_config_st, loadcell); + systemIdentificationMode_b = false; + } + #endif + + + + + + + // if a config update was received over serial, update the variables required for further computation if (configUpdateAvailable == true) @@ -840,21 +879,9 @@ void pedalUpdateTask( void * pvParameters ) } } - - - // if reset pedal position was requested, reset pedal now - // This function is implemented, so that in case of lost steps, the user can request a reset of the pedal psotion - if (resetPedalPosition) { - - if (isv57LifeSignal_b && SENSORLESS_HOMING) - { - stepper->refindMinLimitSensorless(&isv57); - } - - resetPedalPosition = false; - resetServoEncoder = true; - } - + // copy struct to local variable for faster execution + dap_config_pedalUpdateTask_st = dap_config_st; + //#define RECALIBRATE_POSITION #ifdef RECALIBRATE_POSITION @@ -862,90 +889,98 @@ void pedalUpdateTask( void * pvParameters ) #endif - // compute pedal oscillation, when ABS is active - float absForceOffset_fl32 = 0.0f; - + // compute pedal oscillation, when ABS is active float absForceOffset = 0; float absPosOffset = 0; dap_calculationVariables_st.Default_pos(); #ifdef ABS_OSCILLATION - absOscillation.forceOffset(&dap_calculationVariables_st, dap_config_st.payLoadPedalConfig_.absPattern, dap_config_st.payLoadPedalConfig_.absForceOrTarvelBit, &absForceOffset, &absPosOffset); + absOscillation.forceOffset(&dap_calculationVariables_st, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.absPattern, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.absForceOrTarvelBit, &absForceOffset, &absPosOffset); _RPMOscillation.trigger(); _RPMOscillation.forceOffset(&dap_calculationVariables_st); _BitePointOscillation.forceOffset(&dap_calculationVariables_st); - _G_force_effect.forceOffset(&dap_calculationVariables_st, dap_config_st.payLoadPedalConfig_.G_multi); + _G_force_effect.forceOffset(&dap_calculationVariables_st, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.G_multi); _WSOscillation.forceOffset(&dap_calculationVariables_st); - _Road_impact_effect.forceOffset(&dap_calculationVariables_st, dap_config_st.payLoadPedalConfig_.Road_multi); - CV1.forceOffset(dap_config_st.payLoadPedalConfig_.CV_freq_1,dap_config_st.payLoadPedalConfig_.CV_amp_1); - CV2.forceOffset(dap_config_st.payLoadPedalConfig_.CV_freq_2,dap_config_st.payLoadPedalConfig_.CV_amp_2); + _Road_impact_effect.forceOffset(&dap_calculationVariables_st, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.Road_multi); + CV1.forceOffset(dap_config_pedalUpdateTask_st.payLoadPedalConfig_.CV_freq_1,dap_config_pedalUpdateTask_st.payLoadPedalConfig_.CV_amp_1); + CV2.forceOffset(dap_config_pedalUpdateTask_st.payLoadPedalConfig_.CV_freq_2,dap_config_pedalUpdateTask_st.payLoadPedalConfig_.CV_amp_2); + _rudder_g_force.offset_calculate(&dap_calculationVariables_st); + dap_calculationVariables_st.update_stepperMaxpos(_rudder_g_force.offset_filter); _rudder.offset_calculate(&dap_calculationVariables_st); + dap_calculationVariables_st.update_stepperMinpos(_rudder.offset_filter); + + //_rudder.force_offset_calculate(&dap_calculationVariables_st); + #endif //update max force with G force effect - movingAverageFilter.dataPointsCount = dap_config_st.payLoadPedalConfig_.G_window; - movingAverageFilter_roadimpact.dataPointsCount = dap_config_st.payLoadPedalConfig_.Road_window; - dap_calculationVariables_st.reset_maxforce(); - dap_calculationVariables_st.Force_Max += _G_force_effect.G_force; - dap_calculationVariables_st.Force_Max += _Road_impact_effect.Road_Impact_force; - dap_calculationVariables_st.dynamic_update(); - dap_calculationVariables_st.updateStiffness(); - dap_calculationVariables_st.update_stepperpos(_rudder.offset_filter); + movingAverageFilter.dataPointsCount = dap_config_pedalUpdateTask_st.payLoadPedalConfig_.G_window; + movingAverageFilter_roadimpact.dataPointsCount = dap_config_pedalUpdateTask_st.payLoadPedalConfig_.Road_window; + dap_calculationVariables_st.reset_maxforce(); + dap_calculationVariables_st.Force_Max += _G_force_effect.G_force; + dap_calculationVariables_st.Force_Max += _Road_impact_effect.Road_Impact_force; + dap_calculationVariables_st.dynamic_update(); + dap_calculationVariables_st.updateStiffness(); + // Get the loadcell reading float loadcellReading = loadcell->getReadingKg(); // Invert the loadcell reading digitally if desired - if (dap_config_st.payLoadPedalConfig_.invertLoadcellReading_u8 == 1) + if (dap_config_pedalUpdateTask_st.payLoadPedalConfig_.invertLoadcellReading_u8 == 1) { loadcellReading *= -1; } // Convert loadcell reading to pedal force - float sledPosition = sledPositionInMM(stepper, dap_config_st); - float pedalInclineAngleInDeg_fl32 = pedalInclineAngleDeg(sledPosition, dap_config_st); - float pedalForce_fl32 = convertToPedalForce(loadcellReading, sledPosition, dap_config_st); - float d_phi_d_x = convertToPedalForceGain(sledPosition, dap_config_st); + float sledPosition = sledPositionInMM(stepper, &dap_config_pedalUpdateTask_st, motorRevolutionsPerSteps_fl32); + float pedalInclineAngleInDeg_fl32 = pedalInclineAngleDeg(sledPosition, &dap_config_pedalUpdateTask_st); + float pedalForce_fl32 = convertToPedalForce(loadcellReading, sledPosition, &dap_config_pedalUpdateTask_st); + float d_phi_d_x = convertToPedalForceGain(sledPosition, &dap_config_pedalUpdateTask_st); + + // Serial.printf("SledPos:%f, PedalAngle: %f\n", sledPosition, pedalInclineAngleInDeg_fl32); + + // delay(10); // compute gain for horizontal foot model - float b = dap_config_st.payLoadPedalConfig_.lengthPedal_b; - float d = dap_config_st.payLoadPedalConfig_.lengthPedal_d; - float d_x_hor_d_phi = -(b+d) * sinf(pedalInclineAngleInDeg_fl32 * DEG_TO_RAD); + float b = dap_config_pedalUpdateTask_st.payLoadPedalConfig_.lengthPedal_b; + float d = dap_config_pedalUpdateTask_st.payLoadPedalConfig_.lengthPedal_d; + float d_x_hor_d_phi = -(b+d) * sinf(pedalInclineAngleInDeg_fl32 * DEG_TO_RAD_FL32); // Do the loadcell signal filtering - float filteredReading = 0; - float changeVelocity = 0; - + float filteredReading = 0.0f; + float changeVelocity = 0.0f; + float alpha_exp_filter = 1.0f - ( (float)dap_config_pedalUpdateTask_st.payLoadPedalConfig_.kf_modelNoise) / 5000.0f; // const velocity model denoising filter - if (dap_config_st.payLoadPedalConfig_.kf_modelOrder == 0) - { - filteredReading = kalman->filteredValue(pedalForce_fl32, 0, dap_config_st.payLoadPedalConfig_.kf_modelNoise); - changeVelocity = kalman->changeVelocity(); + switch (dap_config_pedalUpdateTask_st.payLoadPedalConfig_.kf_modelOrder) { + case 0: + filteredReading = kalman->filteredValue(pedalForce_fl32, 0, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.kf_modelNoise); + changeVelocity = kalman->changeVelocity(); + break; + case 1: + filteredReading = kalman_2nd_order->filteredValue(pedalForce_fl32, 0, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.kf_modelNoise); + changeVelocity = kalman->changeVelocity(); + break; + case 2: + filteredReading_exp_filter = filteredReading_exp_filter * alpha_exp_filter + pedalForce_fl32 * (1.0-alpha_exp_filter); + filteredReading = filteredReading_exp_filter; + break; + default: + filteredReading_exp_filter = filteredReading_exp_filter * alpha_exp_filter + pedalForce_fl32 * (1.0-alpha_exp_filter); + filteredReading = filteredReading_exp_filter; + break; } - // const acceleration model denoising filter - if (dap_config_st.payLoadPedalConfig_.kf_modelOrder == 1) - { - filteredReading = kalman_2nd_order->filteredValue(pedalForce_fl32, 0, dap_config_st.payLoadPedalConfig_.kf_modelNoise); - changeVelocity = kalman->changeVelocity(); - } - // exponential denoising filter - if (dap_config_st.payLoadPedalConfig_.kf_modelOrder == 2) - { - float alpha_exp_filter = 1.0f - ( (float)dap_config_st.payLoadPedalConfig_.kf_modelNoise) / 5000.0f; - float filteredReading_exp_filter = filteredReading_exp_filter * alpha_exp_filter + pedalForce_fl32 * (1.0-alpha_exp_filter); - filteredReading = filteredReading_exp_filter; - } //#define DEBUG_FILTER - if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_LOADCELL_READING) + if (dap_config_pedalUpdateTask_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_LOADCELL_READING) { static RTDebugOutput rtDebugFilter({ "rawReading_g", "pedalForce_fl32", "filtered_g"}); rtDebugFilter.offerData({ loadcellReading * 1000, pedalForce_fl32*1000, filteredReading * 1000}); @@ -956,35 +991,29 @@ void pedalUpdateTask( void * pvParameters ) //Add effect by force float effect_force = absForceOffset + _BitePointOscillation.BitePoint_Force_offset + _WSOscillation.WS_Force_offset + CV1.CV_Force_offset + CV2.CV_Force_offset; - double stepperPosFraction = stepper->getCurrentPositionFraction(); + float stepperPosFraction = stepper->getCurrentPositionFraction(); int32_t Position_Next = 0; - - - - - // select control loop algo - if (dap_config_st.payLoadPedalConfig_.control_strategy_b <= 1) - { - Position_Next = MoveByPidStrategy(filteredReading, stepperPosFraction, stepper, &forceCurve, &dap_calculationVariables_st, &dap_config_st, 0/*effect_force*/, changeVelocity); - } - - if (dap_config_st.payLoadPedalConfig_.control_strategy_b == 2) - { - Position_Next = MoveByForceTargetingStrategy(filteredReading, stepper, &forceCurve, &dap_calculationVariables_st, &dap_config_st, 0/*effect_force*/, changeVelocity, d_phi_d_x, d_x_hor_d_phi); - } - - + switch (dap_config_pedalUpdateTask_st.payLoadPedalConfig_.control_strategy_b) { + case 0: + Position_Next = MoveByPidStrategy(filteredReading, stepperPosFraction, stepper, &forceCurve, &dap_calculationVariables_st, &dap_config_pedalUpdateTask_st, 0/*effect_force*/, changeVelocity); + break; + case 1: + // int32_t MoveByForceTargetingStrategy(float loadCellReadingKg, StepperWithLimits* stepper, ForceCurve_Interpolated* forceCurve, const DAP_calculationVariables_st* calc_st, DAP_config_st* config_st, float absForceOffset_fl32, float changeVelocity, float d_phi_d_x, float d_x_hor_d_phi) { - //#define DEBUG_STEPPER_POS - if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_STEPPER_POS) - { - static RTDebugOutput rtDebugFilter({ "ESP_pos", "ESP_tar_pos", "ISV_pos", "frac1"}); - rtDebugFilter.offerData({ stepper->getCurrentPositionFromMin(), Position_Next, -(int32_t)(isv57.servo_pos_given_p + isv57.servo_pos_error_p - isv57.getZeroPos()), (int32_t)(stepperPosFraction * 10000.)}); + Position_Next = MoveByForceTargetingStrategy(filteredReading, stepper, &forceCurve, &dap_calculationVariables_st, &dap_config_pedalUpdateTask_st, 0/*effect_force*/, changeVelocity, d_phi_d_x, d_x_hor_d_phi); + break; + default: + Position_Next = MoveByForceTargetingStrategy(filteredReading, stepper, &forceCurve, &dap_calculationVariables_st, &dap_config_pedalUpdateTask_st, 0/*effect_force*/, changeVelocity, d_phi_d_x, d_x_hor_d_phi); + break; } + // float alphaPidOut = 0.9; + // Position_Next = Position_Next*alphaPidOut + Position_Next_Prev * (1.0f - alphaPidOut); + // Position_Next_Prev = Position_Next; + // add dampening if (dap_calculationVariables_st.dampingPress > 0.0001) { @@ -998,15 +1027,15 @@ void pedalUpdateTask( void * pvParameters ) Position_Next = (int32_t)constrain(Position_Next, dap_calculationVariables_st.stepperPosMin, dap_calculationVariables_st.stepperPosMax); - //Adding effects + // //Adding effects int32_t Position_effect= effect_force/dap_calculationVariables_st.Force_Range*dap_calculationVariables_st.stepperPosRange; - Position_Next -=_RPMOscillation.RPM_position_offset; + Position_Next +=_RPMOscillation.RPM_position_offset; Position_Next -= absPosOffset; Position_Next -= Position_effect; Position_Next = (int32_t)constrain(Position_Next, dap_calculationVariables_st.stepperPosMinEndstop, dap_calculationVariables_st.stepperPosMaxEndstop); //bitepoint trigger - int32_t BP_trigger_value = dap_config_st.payLoadPedalConfig_.BP_trigger_value; + int32_t BP_trigger_value = dap_config_pedalUpdateTask_st.payLoadPedalConfig_.BP_trigger_value; int32_t BP_trigger_min = (BP_trigger_value-4); int32_t BP_trigger_max = (BP_trigger_value+4); int32_t Position_check = 100*((Position_Next-dap_calculationVariables_st.stepperPosMin) / dap_calculationVariables_st.stepperPosRange); @@ -1016,7 +1045,7 @@ void pedalUpdateTask( void * pvParameters ) //Serial.println(Position_check); - if(dap_config_st.payLoadPedalConfig_.BP_trigger==1) + if(dap_config_pedalUpdateTask_st.payLoadPedalConfig_.BP_trigger==1) { if(Position_check > BP_trigger_min) { @@ -1027,23 +1056,65 @@ void pedalUpdateTask( void * pvParameters ) } } - // if pedal in min position, recalibrate position - #ifdef ISV_COMMUNICATION - // Take the semaphore and just update the config file, then release the semaphore - if(xSemaphoreTake(semaphore_resetServoPos, (TickType_t)1)==pdTRUE) - { - if (stepper->isAtMinPos()) - { - stepper->correctPos(servo_offset_compensation_steps_i32); - servo_offset_compensation_steps_i32 = 0; - } - xSemaphoreGive(semaphore_resetServoPos); - } - #endif + // if pedal in min position, recalibrate position --> automatic step loss compensation + + stepper->configSteplossRecovAndCrashDetection(dap_config_pedalUpdateTask_st.payLoadPedalConfig_.stepLossFunctionFlags_u8); + if (stepper->isAtMinPos() && OTA_status==false) + { + stepper->correctPos(); + } + + + // print all servo parameters for debug purposes + if ( (dap_config_pedalUpdateTask_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_LOG_ALL_SERVO_PARAMS) ) + { + // clear the debug bit + dap_config_pedalUpdateTask_st.payLoadPedalConfig_.debug_flags_0 &= ( ~(uint8_t)DEBUG_INFO_0_LOG_ALL_SERVO_PARAMS); + delay(1000); + stepper->printAllServoParameters(); + } + + + + // if (pos_printCount == 1000) + // { + // Serial.print("ESP pos: "); + // Serial.print(stepper->getCurrentPosition()); + // Serial.print(", Serovs pos: "); + // Serial.print(stepper->getServosPos()); + // Serial.print(", Serovs pos (corr.): "); + // Serial.println(stepper->getServosInternalPosition()); + // pos_printCount = 0; + // } + // pos_printCount++; + + + + + // Serial.print("Position next: "); + // Serial.println(Position_Next); + + // fiorce stop servo when certain voltage level is exceeded +#ifdef BRAKE_RESISTOR_PIN + if ( stepper->getServosVoltage() > SERVO_VOLTAGE_TO_STOP_MOVEMENT_IN_0p1V) + { + //stepper->forceStop(); + + //stepper->moveTo(dap_calculationVariables_st.stepperPosMaxEndstop, false); + //Serial.println("Resistor high!"); + digitalWrite(BRAKE_RESISTOR_PIN, HIGH); + } + else + { + digitalWrite(BRAKE_RESISTOR_PIN, LOW); + } + #endif - // Move to new position + // Move to new position + if(OTA_status==false) + { if (!moveSlowlyToPosition_b) { stepper->moveTo(Position_Next, false); @@ -1053,6 +1124,11 @@ void pedalUpdateTask( void * pvParameters ) moveSlowlyToPosition_b = false; stepper->moveSlowlyToPos(Position_Next); } + } + + + + // compute controller output @@ -1070,27 +1146,25 @@ void pedalUpdateTask( void * pvParameters ) if(dap_calculationVariables_st.Rudder_status&&dap_calculationVariables_st.rudder_brake_status) { - if (1 == dap_config_st.payLoadPedalConfig_.travelAsJoystickOutput_u8) + if (1 == dap_config_pedalUpdateTask_st.payLoadPedalConfig_.travelAsJoystickOutput_u8) { - //joystickNormalizedToInt32 = NormalizeControllerOutputValue((Position_Next-dap_calculationVariables_st.stepperPosRange/2), dap_calculationVariables_st.stepperPosMin, dap_calculationVariables_st.stepperPosMin+dap_calculationVariables_st.stepperPosRange/2, dap_config_st.payLoadPedalConfig_.maxGameOutput); joystickNormalizedToInt32 = NormalizeControllerOutputValue((Position_Next-dap_calculationVariables_st.stepperPosRange/2), dap_calculationVariables_st.stepperPosMin, dap_calculationVariables_st.stepperPosMin+dap_calculationVariables_st.stepperPosRange/2, dap_config_st.payLoadPedalConfig_.maxGameOutput); joystickNormalizedToInt32 = constrain(joystickNormalizedToInt32,0,JOYSTICK_MAX_VALUE); } else { - //joystickNormalizedToInt32 = NormalizeControllerOutputValue(loadcellReading, dap_calculationVariables_st.Force_Min, dap_calculationVariables_st.Force_Max, dap_config_st.payLoadPedalConfig_.maxGameOutput); - joystickNormalizedToInt32 = NormalizeControllerOutputValue((filteredReading), dap_calculationVariables_st.Force_Min, dap_calculationVariables_st.Force_Max, dap_config_st.payLoadPedalConfig_.maxGameOutput); + joystickNormalizedToInt32 = NormalizeControllerOutputValue((filteredReading), dap_calculationVariables_st.Force_Min, dap_calculationVariables_st.Force_Max, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.maxGameOutput); } } else { - if (1 == dap_config_st.payLoadPedalConfig_.travelAsJoystickOutput_u8) + if (1 == dap_config_pedalUpdateTask_st.payLoadPedalConfig_.travelAsJoystickOutput_u8) { - joystickNormalizedToInt32 = NormalizeControllerOutputValue(Position_Next, dap_calculationVariables_st.stepperPosMin, dap_calculationVariables_st.stepperPosMax, dap_config_st.payLoadPedalConfig_.maxGameOutput); + joystickNormalizedToInt32 = NormalizeControllerOutputValue(Position_Next, dap_calculationVariables_st.stepperPosMin, dap_calculationVariables_st.stepperPosMax, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.maxGameOutput); } else { - joystickNormalizedToInt32 = NormalizeControllerOutputValue(filteredReading, dap_calculationVariables_st.Force_Min, dap_calculationVariables_st.Force_Max, dap_config_st.payLoadPedalConfig_.maxGameOutput); + joystickNormalizedToInt32 = NormalizeControllerOutputValue(filteredReading, dap_calculationVariables_st.Force_Min, dap_calculationVariables_st.Force_Max, dap_config_pedalUpdateTask_st.payLoadPedalConfig_.maxGameOutput); } } @@ -1124,9 +1198,9 @@ void pedalUpdateTask( void * pvParameters ) } // simulate ABS trigger - if(dap_config_st.payLoadPedalConfig_.Simulate_ABS_trigger==1) + if(dap_config_pedalUpdateTask_st.payLoadPedalConfig_.Simulate_ABS_trigger==1) { - int32_t ABS_trigger_value=dap_config_st.payLoadPedalConfig_.Simulate_ABS_value; + int32_t ABS_trigger_value=dap_config_pedalUpdateTask_st.payLoadPedalConfig_.Simulate_ABS_value; if( (normalizedPedalReading_fl32*100) > ABS_trigger_value) { absOscillation.trigger(); @@ -1134,7 +1208,7 @@ void pedalUpdateTask( void * pvParameters ) } - +//#ifdef UNCOMMENT // update pedal states if(semaphore_updatePedalStates!=NULL) { @@ -1149,7 +1223,7 @@ void pedalUpdateTask( void * pvParameters ) dap_state_basic_st.payLoadHeader_.payloadType = DAP_PAYLOAD_TYPE_STATE_BASIC; dap_state_basic_st.payLoadHeader_.version = DAP_VERSION_CONFIG; dap_state_basic_st.payloadFooter_.checkSum = checksumCalculator((uint8_t*)(&(dap_state_basic_st.payLoadHeader_)), sizeof(dap_state_basic_st.payLoadHeader_) + sizeof(dap_state_basic_st.payloadPedalState_Basic_)); - dap_state_basic_st.payLoadHeader_.PedalTag=dap_config_st.payLoadPedalConfig_.pedal_type; + dap_state_basic_st.payLoadHeader_.PedalTag=dap_config_pedalUpdateTask_st.payLoadPedalConfig_.pedal_type; //error code dap_state_basic_st.payloadPedalState_Basic_.erroe_code_u8=0; @@ -1159,15 +1233,14 @@ void pedalUpdateTask( void * pvParameters ) ESPNow_error_code=0; } //dap_state_basic_st.payloadPedalState_Basic_.erroe_code_u8=200; - if(isv57.isv57_update_parameter_b) + /*if(isv57.isv57_update_parameter_b) { dap_state_basic_st.payloadPedalState_Basic_.erroe_code_u8=11; isv57.isv57_update_parameter_b=false; - } - if(isv57_not_live_b) + }*/ + if( stepper->getLifelineSignal()==false ) { dap_state_basic_st.payloadPedalState_Basic_.erroe_code_u8=12; - isv57_not_live_b=false; } // update extended struct dap_state_extended_st.payloadPedalState_Extended_.timeInMs_u32 = millis(); @@ -1175,23 +1248,16 @@ void pedalUpdateTask( void * pvParameters ) dap_state_extended_st.payloadPedalState_Extended_.pedalForce_filtered_fl32 = filteredReading; dap_state_extended_st.payloadPedalState_Extended_.forceVel_est_fl32 = changeVelocity; - if(semaphore_readServoValues!=NULL) - { - if(xSemaphoreTake(semaphore_readServoValues, (TickType_t)1)==pdTRUE) { - dap_state_extended_st.payloadPedalState_Extended_.servoPosition_i16 = servoPos_i16; - dap_state_extended_st.payloadPedalState_Extended_.servo_voltage_0p1V = isv57.servo_voltage_0p1V; - dap_state_extended_st.payloadPedalState_Extended_.servo_current_percent_i16 = isv57.servo_current_percent; - - xSemaphoreGive(semaphore_readServoValues); - } - } - else - { - semaphore_readServoValues = xSemaphoreCreateMutex(); - } + //dap_state_extended_st.payloadPedalState_Extended_.servoPosition_i16 = stepper->getServosInternalPosition(); + dap_state_extended_st.payloadPedalState_Extended_.servoPosition_i16 = stepper->getServosInternalPositionCorrected()- stepper->getMinPosition(); + dap_state_extended_st.payloadPedalState_Extended_.servo_voltage_0p1V = stepper->getServosVoltage(); + dap_state_extended_st.payloadPedalState_Extended_.servo_current_percent_i16 = stepper->getServosCurrent(); + - dap_state_extended_st.payloadPedalState_Extended_.servoPositionTarget_i16 = stepper->getCurrentPositionFromMin(); - dap_state_extended_st.payLoadHeader_.PedalTag=dap_config_st.payLoadPedalConfig_.pedal_type; + + //dap_state_extended_st.payloadPedalState_Extended_.servoPositionTarget_i16 = stepper->getCurrentPositionFromMin(); + dap_state_extended_st.payloadPedalState_Extended_.servoPositionTarget_i16 = stepper->getCurrentPosition() - stepper->getMinPosition(); + dap_state_extended_st.payLoadHeader_.PedalTag=dap_config_pedalUpdateTask_st.payLoadPedalConfig_.pedal_type; dap_state_extended_st.payLoadHeader_.payloadType = DAP_PAYLOAD_TYPE_STATE_EXTENDED; dap_state_extended_st.payLoadHeader_.version = DAP_VERSION_CONFIG; dap_state_extended_st.payloadFooter_.checkSum = checksumCalculator((uint8_t*)(&(dap_state_extended_st.payLoadHeader_)), sizeof(dap_state_extended_st.payLoadHeader_) + sizeof(dap_state_extended_st.payloadPedalState_Extended_)); @@ -1204,7 +1270,19 @@ void pedalUpdateTask( void * pvParameters ) { semaphore_updatePedalStates = xSemaphoreCreateMutex(); } - + +// #endif + + #ifdef PRINT_TASK_FREE_STACKSIZE_IN_WORDS + if( controlTask_stackSizeIdx_u32 == 1000) + { + UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL); + Serial.print("StackSize (Pedal update): "); + Serial.println(stackHighWaterMark); + controlTask_stackSizeIdx_u32 = 0; + } + controlTask_stackSizeIdx_u32++; + #endif } } @@ -1224,9 +1302,7 @@ void pedalUpdateTask( void * pvParameters ) /* communication task */ /* */ /**********************************************************************************************/ - - - +uint32_t communicationTask_stackSizeIdx_u32 = 0; int64_t timeNow_serialCommunicationTask_l = 0; int64_t timePrevious_serialCommunicationTask_l = 0; #define REPETITION_INTERVAL_SERIALCOMMUNICATION_TASK (int64_t)10 @@ -1315,7 +1391,10 @@ void serialCommunicationTask( void * pvParameters ) if (structChecker == true) { Serial.println("Updating pedal config"); - configUpdateAvailable = true; + configUpdateAvailable = true; + #ifdef USING_BUZZER + Buzzer.single_beep_tone(700,100); + #endif } xSemaphoreGive(semaphore_updateConfig); } @@ -1356,14 +1435,10 @@ void serialCommunicationTask( void * pvParameters ) if (structChecker == true) { - // trigger reset pedal position - if (dap_actions_st.payloadPedalAction_.system_action_u8==1) - { - resetPedalPosition = true; - } //2= restart pedal if (dap_actions_st.payloadPedalAction_.system_action_u8==2) { + Serial.println("ESP restart by user request"); ESP.restart(); } //3= Wifi OTA @@ -1377,8 +1452,13 @@ void serialCommunicationTask( void * pvParameters ) //4 Enable pairing if (dap_actions_st.payloadPedalAction_.system_action_u8==4) { - Serial.println("Get Pairing command"); - software_pairing_action_b=true; + #ifdef ESPNow_Pairing_function + Serial.println("Get Pairing command"); + software_pairing_action_b=true; + #endif + #ifndef ESPNow_Pairing_function + Serial.println("no supporting command"); + #endif } // trigger ABS effect @@ -1396,7 +1476,15 @@ void serialCommunicationTask( void * pvParameters ) _WSOscillation.trigger(); } //Road impact - _Road_impact_effect.Road_Impact_value=dap_actions_st.payloadPedalAction_.impact_value_u8; + if(dap_calculationVariables_st.Rudder_status==false) + { + _Road_impact_effect.Road_Impact_value=dap_actions_st.payloadPedalAction_.impact_value_u8; + } + else + { + + } + // trigger system identification if (dap_actions_st.payloadPedalAction_.startSystemIdentification_u8) { @@ -1464,7 +1552,23 @@ void serialCommunicationTask( void * pvParameters ) } break; - + case sizeof(Basic_WIfi_info) : + Serial.println("get basic wifi info"); + Serial.readBytes((char*)&_basic_wifi_info, sizeof(Basic_WIfi_info)); + #ifdef OTA_update + if(_basic_wifi_info.device_ID==dap_config_st.payLoadPedalConfig_.pedal_type) + { + SSID=new char[_basic_wifi_info.SSID_Length+1]; + PASS=new char[_basic_wifi_info.PASS_Length+1]; + memcpy(SSID,_basic_wifi_info.WIFI_SSID,_basic_wifi_info.SSID_Length); + memcpy(PASS,_basic_wifi_info.WIFI_PASS,_basic_wifi_info.PASS_Length); + SSID[_basic_wifi_info.SSID_Length]=0; + PASS[_basic_wifi_info.PASS_Length]=0; + OTA_enable_b=true; + } + #endif + + break; default: // flush the input buffer @@ -1556,19 +1660,34 @@ void serialCommunicationTask( void * pvParameters ) } } + #ifdef PRINT_TASK_FREE_STACKSIZE_IN_WORDS + if( communicationTask_stackSizeIdx_u32 == 1000) + { + UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL); + Serial.print("StackSize (Serial communication): "); + Serial.println(stackHighWaterMark); + communicationTask_stackSizeIdx_u32 = 0; + } + communicationTask_stackSizeIdx_u32++; + #endif + } } -//OTA multitask + + +//OTA multitask uint16_t OTA_count=0; bool message_out_b=false; bool OTA_enable_start=false; +uint32_t otaTask_stackSizeIdx_u32 = 0; +int OTA_update_status=99; void OTATask( void * pvParameters ) { for(;;) { - #ifdef OTA_update + if(OTA_count>200) { message_out_b=true; @@ -1579,7 +1698,7 @@ void OTATask( void * pvParameters ) OTA_count++; } - + #if defined(OTA_update) || defined(OTA_update_ESP32) if(OTA_enable_b) { if(message_out_b) @@ -1589,8 +1708,35 @@ void OTATask( void * pvParameters ) } if(OTA_status) { + #ifdef OTA_update_ESP32 + server.handleClient(); + #endif + #ifdef OTA_update + if(OTA_update_status==0) + { + #ifdef USING_BUZZER + Buzzer.play_melody_tone(melody_victory_theme, sizeof(melody_victory_theme)/sizeof(melody_victory_theme[0]),melody_durations_Victory_theme); + #endif + ESP.restart(); + } + else + { + #ifdef USING_BUZZER + Buzzer.single_beep_tone(770,100); + #endif + #ifdef USING_LED + pixels.setPixelColor(0,0xff,0x00,0x00);//red + pixels.show(); + delay(500); + pixels.setPixelColor(0,0x00,0x00,0x00);//no color + pixels.show(); + delay(500); + #endif + } + + #endif - server.handleClient(); + } else { @@ -1599,12 +1745,60 @@ void OTATask( void * pvParameters ) esp_err_t result= esp_now_deinit(); ESPNow_initial_status=false; ESPNOW_status=false; - delay(200); + delay(3000); if(result==ESP_OK) { OTA_status=true; + #ifdef USING_BUZZER + Buzzer.single_beep_tone(700,100); + #endif delay(1000); + #ifdef OTA_update_ESP32 ota_wifi_initialize(APhost); + #endif + #ifdef USING_LED + //pixels.setBrightness(20); + pixels.setPixelColor(0,0x00,0x00,0xff);//Blue + pixels.show(); + //delay(3000); + #endif + #ifdef OTA_update + wifi_initialized(SSID,PASS); + delay(2000); + ESP32OTAPull ota; + int ret; + ota.SetCallback(OTAcallback); + ota.OverrideBoard(CONTROL_BOARD); + char* version_tag; + if(_basic_wifi_info.wifi_action==1) + { + version_tag="0.0.0"; + Serial.println("Force update"); + } + else + { + version_tag=DAP_FIRMWARE_VERSION; + } + switch (_basic_wifi_info.mode_select) + { + case 1: + Serial.printf("Flashing to latest Main, checking %s to see if an update is available...\n", JSON_URL_main); + ret = ota.CheckForOTAUpdate(JSON_URL_main, version_tag, ESP32OTAPull::UPDATE_BUT_NO_BOOT); + Serial.printf("CheckForOTAUpdate returned %d (%s)\n\n", ret, errtext(ret)); + OTA_update_status=ret; + break; + case 2: + Serial.printf("Flashing to latest Dev, checking %s to see if an update is available...\n", JSON_URL_dev); + ret = ota.CheckForOTAUpdate(JSON_URL_dev, version_tag, ESP32OTAPull::UPDATE_BUT_NO_BOOT); + Serial.printf("CheckForOTAUpdate returned %d (%s)\n\n", ret, errtext(ret)); + OTA_update_status=ret; + break; + default: + break; + } + #endif + + delay(3000); } } @@ -1612,6 +1806,18 @@ void OTATask( void * pvParameters ) delay(1); #endif + + #ifdef PRINT_TASK_FREE_STACKSIZE_IN_WORDS + if( otaTask_stackSizeIdx_u32 == 1000) + { + UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL); + Serial.print("StackSize (OTA): "); + Serial.println(stackHighWaterMark); + otaTask_stackSizeIdx_u32 = 0; + } + otaTask_stackSizeIdx_u32++; + #endif + delay(2); } } @@ -1633,6 +1839,9 @@ bool Pairing_timeout_status=false; bool building_dap_esppairing_lcl =false; unsigned long Pairing_state_start; unsigned long Pairing_state_last_sending; +unsigned long Debug_rudder_last=0; + +uint32_t espNowTask_stackSizeIdx_u32 = 0; void ESPNOW_SyncTask( void * pvParameters ) { for(;;) @@ -1645,11 +1854,16 @@ void ESPNOW_SyncTask( void * pvParameters ) uint32_t targetWaitTime_u32 = constrain(timeDiff_espNowTask_l, 0, REPETITION_INTERVAL_ESPNOW_TASK); delay(targetWaitTime_u32); timePrevious_espNowTask_l = millis(); + + //restart from espnow if(ESPNow_restart) { + Serial.println("ESP restart by ESP now request"); ESP.restart(); } + + //basic state sendout interval if(ESPNOW_count%9==0) { @@ -1681,7 +1895,13 @@ void ESPNOW_SyncTask( void * pvParameters ) else { #ifdef ESPNow_Pairing_function - if(digitalRead(Pairing_GPIO)==LOW||software_pairing_action_b) + #ifdef Hardware_Pairing_button + if(digitalRead(Pairing_GPIO)==LOW) + { + hardware_pairing_action_b=true; + } + #endif + if(hardware_pairing_action_b||software_pairing_action_b) { Serial.println("Pedal Pairing....."); delay(1000); @@ -1690,6 +1910,7 @@ void ESPNOW_SyncTask( void * pvParameters ) ESPNow_pairing_action_b=true; building_dap_esppairing_lcl=true; software_pairing_action_b=false; + hardware_pairing_action_b=false; } if(ESPNow_pairing_action_b) @@ -1719,7 +1940,12 @@ void ESPNOW_SyncTask( void * pvParameters ) if(now-Pairing_state_start>Pairing_timeout) { ESPNow_pairing_action_b=false; - Serial.println("Reach timeout"); + Serial.print("Pedal: "); + Serial.print(dap_config_st.payLoadPedalConfig_.pedal_type); + Serial.println(" timeout."); + #ifdef USING_BUZZER + Buzzer.single_beep_tone(700,100); + #endif if(UpdatePairingToEeprom) { EEPROM.put(EEPROM_offset,_ESP_pairing_reg); @@ -1806,6 +2032,13 @@ void ESPNOW_SyncTask( void * pvParameters ) ESPNow.send_message(broadcast_mac,(uint8_t *) & dap_config_st,sizeof(dap_config_st)); ESPNow_config_request=false; } + if(Config_update_b) + { + Config_update_b=false; + #ifdef USING_BUZZER + Buzzer.single_beep_tone(700,100); + #endif + } if(ESPNow_OTA_enable) { Serial.println("Get OTA command"); @@ -1813,7 +2046,28 @@ void ESPNOW_SyncTask( void * pvParameters ) OTA_enable_start=true; ESPNow_OTA_enable=false; } - + if(OTA_update_action_b) + { + Serial.println("Get OTA command"); + OTA_enable_b=true; + OTA_enable_start=true; + ESPNow_OTA_enable=false; + Serial.println("get basic wifi info"); + Serial.readBytes((char*)&_basic_wifi_info, sizeof(Basic_WIfi_info)); + #ifdef OTA_update + if(_basic_wifi_info.device_ID==dap_config_st.payLoadPedalConfig_.pedal_type) + { + SSID=new char[_basic_wifi_info.SSID_Length+1]; + PASS=new char[_basic_wifi_info.PASS_Length+1]; + memcpy(SSID,_basic_wifi_info.WIFI_SSID,_basic_wifi_info.SSID_Length); + memcpy(PASS,_basic_wifi_info.WIFI_PASS,_basic_wifi_info.PASS_Length); + SSID[_basic_wifi_info.SSID_Length]=0; + PASS[_basic_wifi_info.PASS_Length]=0; + OTA_enable_b=true; + } + #endif + + } //rudder sync if(dap_calculationVariables_st.Rudder_status) { @@ -1837,22 +2091,33 @@ void ESPNOW_SyncTask( void * pvParameters ) } - - #ifdef ESPNow_debug - if(print_count>1500) + #ifdef ESPNow_debug_rudder + if(print_count>1000) { - Serial.print("Rudder Status:"); - Serial.println(dap_calculationVariables_st.Rudder_status); - Serial.print("Pedal type:"); - Serial.println(dap_config_st.payLoadPedalConfig_.pedal_type); - Serial.print("---Sync Value--"); - Serial.println(dap_calculationVariables_st.sync_pedal_position); - Serial.print("---Recieve Value--"); - Serial.println(_ESPNow_Recv.pedal_position_ratio); - Serial.print("---Send Value--"); - Serial.println(dap_calculationVariables_st.current_pedal_position); + if(dap_calculationVariables_st.Rudder_status) + { + Serial.print("Pedal:"); + Serial.print(dap_config_st.payLoadPedalConfig_.pedal_type); + Serial.print(", Send %: "); + Serial.print(_ESPNow_Send.pedal_position_ratio); + Serial.print(", Recieve %:"); + Serial.print(_ESPNow_Recv.pedal_position_ratio); + Serial.print(", Send Position: "); + Serial.print(dap_calculationVariables_st.current_pedal_position); + Serial.print(", % in cal: "); + Serial.print(dap_calculationVariables_st.current_pedal_position_ratio); + Serial.print(", min cal: "); + Serial.print(dap_calculationVariables_st.stepperPosMin_default); + Serial.print(", max cal: "); + Serial.print(dap_calculationVariables_st.stepperPosMax_default); + Serial.print(", range in cal: "); + Serial.println(dap_calculationVariables_st.stepperPosRange_default); + } + + //Debug_rudder_last=now_rudder; + //Serial.println(dap_calculationVariables_st.current_pedal_position); - print_count=0; + print_count=0; } else { @@ -1862,246 +2127,23 @@ void ESPNOW_SyncTask( void * pvParameters ) #endif - //delay(1); - } -} -#endif - - -#ifdef ISV_COMMUNICATION - - -int16_t servoPos_last_i16 = 0; -int64_t timeSinceLastServoPosChange_l = 0; -int64_t timeNow_l = 0; -int64_t timeDiff = 0; - -#define TIME_SINCE_SERVO_POS_CHANGE_TO_DETECT_STANDSTILL_IN_MS 200 - -bool previousIsv57LifeSignal_b = true; - -uint64_t print_cycle_counter_u64 = 0; -unsigned long cycleTimeLastCall_lifelineCheck = 0;//micros(); -void servoCommunicationTask( void * pvParameters ) -{ - - for(;;){ - delay(1); - if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_CYCLE_TIMER) - { - static CycleTimer timerServoCommunication("Servo Com. cycle time"); - timerServoCommunication.Bump(); - } - - // check if servo communication is still there every N milliseconds - unsigned long now = millis(); - if ( (now - cycleTimeLastCall_lifelineCheck) > 500) - { - // if target cycle time is reached, update last time - cycleTimeLastCall_lifelineCheck = now; - - isv57LifeSignal_b = isv57.checkCommunication(); - //Serial.println("Lifeline check"); - } - - if (isv57LifeSignal_b) - { - - - // when servo was restarted, the read states need to be initialized first - if (false == previousIsv57LifeSignal_b) - { - isv57.setupServoStateReading(); - previousIsv57LifeSignal_b = true; - delay(50); - } - - - isv57.readServoStates(); - - if(semaphore_readServoValues!=NULL) - { - if(xSemaphoreTake(semaphore_readServoValues, (TickType_t)1)==pdTRUE) { - servoPos_i16 = -( isv57.servo_pos_given_p - isv57.getZeroPos() ); - xSemaphoreGive(semaphore_readServoValues); - } - } - else - { - semaphore_readServoValues = xSemaphoreCreateMutex(); - } - - int32_t servo_offset_compensation_steps_local_i32 = 0; - - // condition 1: servo must be at halt - // condition 2: the esp accel lib must be at halt - bool cond_1 = false; - bool cond_2 = false; - - // check whether target position from ESP hasn't changed and is at min endstop position - cond_2 = stepper->isAtMinPos(); - - - - if (cond_2 == true) - { - //isv57.readServoStates(); - int16_t servoPos_now_i16 = isv57.servo_pos_given_p; - timeNow_l = millis(); - - // check whether servo position has changed, in case, update the halt detection variable - if (servoPos_last_i16 != servoPos_now_i16) - { - servoPos_last_i16 = servoPos_now_i16; - timeSinceLastServoPosChange_l = timeNow_l; - } - - // compute the time difference since last servo position change - timeDiff = timeNow_l - timeSinceLastServoPosChange_l; - - // if time between last servo position is larger than a threshold, detect servo standstill - if ( (timeDiff > TIME_SINCE_SERVO_POS_CHANGE_TO_DETECT_STANDSTILL_IN_MS) - && (timeNow_l > 0) ) - { - cond_1 = true; - } - else - { - cond_1 = false; - } - } - - - - - - // calculate zero position offset - if (cond_1 && cond_2) - { - - // reset encoder position, when pedal is at min position - if (resetServoEncoder == true) - { - isv57.setZeroPos(); - resetServoEncoder = false; - } - - // calculate encoder offset - // movement to the back will reduce encoder value - servo_offset_compensation_steps_local_i32 = (int32_t)isv57.getZeroPos() - (int32_t)isv57.servo_pos_given_p; - // when pedal has moved to the back due to step losses --> offset will be positive - - - - - - // When the servo turned off during driving, the servo loses its zero position and the correction might not be valid anymore. If still applied, the servo will somehow srive against the block - // resulting in excessive servo load --> current load. We'll detect whether min or max block was reached, depending on the position error sign - bool servoCurrentLow_b = abs(isv57.servo_current_percent) < 200; - if (!servoCurrentLow_b) - { - - // positive current means positive rotation - bool minBlockCrashDetected_b = false; - bool maxBlockCrashDetected_b = false; - if (isv57.servo_current_percent > 0) // if current is positive, the rotation will be positive and thus the sled will move towards the user - { - minBlockCrashDetected_b = true; - isv57.applyOfsetToZeroPos(-500); // bump up a bit to prevent the servo from pushing against the endstop continously - } - else - { - maxBlockCrashDetected_b = true; - isv57.applyOfsetToZeroPos(500); // bump up a bit to prevent the servo from pushing against the endstop continously - } - /*print_cycle_counter_u64++; - print_cycle_counter_u64 %= 10; - - if (print_cycle_counter_u64 == 0) - { - Serial.print("minDet: "); - Serial.print(minBlockCrashDetected_b); - - Serial.print("curr: "); - Serial.print(isv57.servo_current_percent); - - Serial.print("posError: "); - Serial.print(isv57.servo_pos_error_p); - - Serial.println(); - }*/ - - - //servo_offset_compensation_steps_local_i32 = isv57.servo_pos_error_p; - } - - - - - - // since the encoder positions are defined in int16 space, they wrap at multiturn - // to correct overflow, we apply modulo to take smallest possible deviation - if (servo_offset_compensation_steps_local_i32 > pow(2,15)-1) - { - servo_offset_compensation_steps_local_i32 -= pow(2,16); - } - - if (servo_offset_compensation_steps_local_i32 < -pow(2,15)) - { - servo_offset_compensation_steps_local_i32 += pow(2,16); - } - } - - - // invert the compensation wrt the motor direction - if (dap_config_st.payLoadPedalConfig_.invertMotorDirection_u8 == 1) - { - servo_offset_compensation_steps_local_i32 *= -1; - } - - - if(semaphore_resetServoPos!=NULL) - { - - // Take the semaphore and just update the config file, then release the semaphore - if(xSemaphoreTake(semaphore_resetServoPos, (TickType_t)1)==pdTRUE) - { - servo_offset_compensation_steps_i32 = servo_offset_compensation_steps_local_i32; - xSemaphoreGive(semaphore_resetServoPos); - } - - } - else - { - semaphore_resetServoPos = xSemaphoreCreateMutex(); - //Serial.println("semaphore_resetServoPos == 0"); - } - - - - if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_SERVO_READINGS) + + #ifdef PRINT_TASK_FREE_STACKSIZE_IN_WORDS + if( espNowTask_stackSizeIdx_u32 == 1000) { - static RTDebugOutput rtDebugFilter({ "pos_p", "pos_error_p", "curr_per", "offset"}); - rtDebugFilter.offerData({ isv57.servo_pos_given_p, isv57.servo_pos_error_p, isv57.servo_current_percent, (int16_t)servo_offset_compensation_steps_i32}); + UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL); + Serial.print("StackSize (ESP-Now): "); + Serial.println(stackHighWaterMark); + espNowTask_stackSizeIdx_u32 = 0; } - - - - - } - else - { - Serial.println("Servo communication lost!"); - delay(100); - previousIsv57LifeSignal_b = false; - isv57_not_live_b=true; - } - - + espNowTask_stackSizeIdx_u32++; + #endif } -} +} #endif + + diff --git a/ESP32/src/Modbus.cpp b/ESP32/src/Modbus.cpp index cb6ac7d0..ec551065 100644 --- a/ESP32/src/Modbus.cpp +++ b/ESP32/src/Modbus.cpp @@ -95,56 +95,77 @@ void Modbus::readParameter(uint16_t slaveId_local_u16, uint16_t parameterAdress) // if value is not target value --> overwrite value - Serial.print("Parameter address: "); - Serial.print(parameterAdress); - Serial.print(", actual:"); - Serial.println(returnValue); + Serial.print("Parameter address: "); + Serial.print(parameterAdress); + Serial.print(", actual:"); + Serial.println(returnValue); - delay(50); + delay(50); } // check target values at register address. If target value was already present, return 0. If target value has to be set, return 1. bool Modbus::checkAndReplaceParameter(uint16_t slaveId_local_u16, uint16_t parameterAdress, long value) { - bool retValue_b = false; + bool registerWritten_b = false; + bool registerValueAsTarget_b = false; - // check if value at address is already target value - uint8_t raw2[2]; - uint8_t len; - int16_t regArray[4]; + - // read the four registers simultaneously - if(requestFrom(slaveId_local_u16, 0x03, parameterAdress, 2) > 0) + // check and set the register at maximum N times + for (uint8_t tryIdx_u8 = 0; tryIdx_u8 < 10; tryIdx_u8++) { - RxRaw(raw2, len); - regArray[0] = uint16(0); - } - - // write to public variables - int16_t returnValue = regArray[0]; + + if (true == registerValueAsTarget_b) + { + // when register has proper setting, break the loop + break; + } + delay(10); + // check if value at address is already target value + uint8_t raw2[2]; + uint8_t len; + int16_t regArray[4]; - // if value is not target value --> overwrite value - if(returnValue!= value) - { - Serial.print("Parameter adresse: "); - Serial.print(parameterAdress); - Serial.print(", actual:"); - Serial.print(returnValue); - Serial.print(", target:"); - Serial.println(value); + // read the four registers simultaneously + if(requestFrom(slaveId_local_u16, 0x03, parameterAdress, 2) > 0) + { + RxRaw(raw2, len); + regArray[0] = uint16(0); + } + + // write to public variables + int16_t returnValue = regArray[0]; + + long targetValue_l = value; + + // if value is not target value --> overwrite value + if(returnValue!= targetValue_l) + { + delay(30); + Serial.print("Parameter adresse: "); + Serial.print(parameterAdress); + Serial.print(", actual: "); + Serial.print(returnValue); + Serial.print(", target: "); + Serial.println(targetValue_l); + holdingRegisterWrite(slaveId_local_u16, parameterAdress, targetValue_l); + + registerWritten_b = true; + } + else + { + registerValueAsTarget_b = true; + } - holdingRegisterWrite(slaveId_local_u16, parameterAdress, value); // deactivate auto gain - delay(50); - retValue_b = true; } - return retValue_b; + return registerWritten_b; } @@ -197,7 +218,7 @@ long Modbus::inputRegisterRead(int id, int address, int block) } - + @@ -238,8 +259,9 @@ int Modbus::requestFrom(int slaveId, int type, int address, int nb) int ll = 0; int rx; uint8_t found = 0; - - while((millis() - t) < timeout_){ + + bool allDataReceived_b = false; + while( (false == allDataReceived_b) && ((millis() - t) < timeout_)){ if(this->s->available()) { rx = this->s->read(); @@ -274,7 +296,10 @@ int Modbus::requestFrom(int slaveId, int type, int address, int nb) // Byte N: CRC LSB // The total message length is thus N = 5+m - if(lenRx >= rawRx[2] + 5) { break; } + if(lenRx >= rawRx[2] + 5) { + allDataReceived_b = true; + break; + } } } @@ -508,16 +533,47 @@ int Modbus::holdingRegisterWrite(int id, int address, uint16_t value) // send signal digitalWrite(mode_,1); - delay(1); - this->s->write(txout,8); - this->s->flush(); - digitalWrite(mode_,0); - delay(1); - - - return 1; - - - + delay(1); + this->s->write(txout,8); + this->s->flush(); + digitalWrite(mode_,0); + delay(1); + + // verify return signal + // should be identical to transmit signal, otherwise error + + uint32_t t = millis(); + int ll = 0; + int rx; + + bool returnSignalIsCopyOfTransmittedSignal_b = false; + while((millis() - t) < timeout_){ + if(this->s->available()) + { + rx = this->s->read(); + t = millis(); + + if(txout[ll] == rx){ll++;}else{ll = 0;} + + if (ll == 8) + { + returnSignalIsCopyOfTransmittedSignal_b = true; + break; + } + + } + } + + // Serial.print("Returnsignal: "); + // Serial.print(returnSignalIsCopyOfTransmittedSignal_b); + // Serial.print(", Adress: "); + // Serial.print(address); + // Serial.print(", value: "); + // Serial.println(value); + + delay(5); + + return returnSignalIsCopyOfTransmittedSignal_b; + } \ No newline at end of file diff --git a/ESP32/src/PedalGeometry.cpp b/ESP32/src/PedalGeometry.cpp index 5e7f57c3..6ad1be0a 100644 --- a/ESP32/src/PedalGeometry.cpp +++ b/ESP32/src/PedalGeometry.cpp @@ -1,6 +1,7 @@ #include "PedalGeometry.h" #include "StepperWithLimits.h" +//#include "FastTrig.h" KALMAN<3,1> K_pedal_geometry; unsigned long _timeLastObservation; @@ -13,29 +14,26 @@ static const float KF_MODEL_NOISE_FORCE_ACCELERATION = ( 10000000000. ); 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};*/ - - - - - -float sledPositionInMM(StepperWithLimits* stepper, DAP_config_st& config_st) { +float sledPositionInMM(StepperWithLimits* stepper, DAP_config_st * config_st, float motorRevolutionsPerStep_fl32) { float currentPos = stepper->getCurrentPositionFromMin(); - //return (currentPos / STEPS_PER_MOTOR_REVOLUTION) * TRAVEL_PER_ROTATION_IN_MM; - return (currentPos / (float)STEPS_PER_MOTOR_REVOLUTION) * config_st.payLoadPedalConfig_.spindlePitch_mmPerRev_u8; - + return currentPos * motorRevolutionsPerStep_fl32 * config_st->payLoadPedalConfig_.spindlePitch_mmPerRev_u8; +} + +float sledPositionInMM_withPositionAsArgument(float currentPos_fl32, DAP_config_st * config_st, float motorRevolutionsPerStep_fl32) { + return currentPos_fl32 * motorRevolutionsPerStep_fl32 * config_st->payLoadPedalConfig_.spindlePitch_mmPerRev_u8; } -float pedalInclineAngleDeg(float sledPositionMM, DAP_config_st& config_st) { +float pedalInclineAngleDeg(float sledPositionMM, DAP_config_st * config_st) { // see https://de.wikipedia.org/wiki/Kosinussatz // A: is lower pedal pivot // C: is upper pedal pivot // B: is rear pedal pivot - float a = config_st.payLoadPedalConfig_.lengthPedal_a; - float b = config_st.payLoadPedalConfig_.lengthPedal_b; - float c_ver = config_st.payLoadPedalConfig_.lengthPedal_c_vertical; - float c_hor = config_st.payLoadPedalConfig_.lengthPedal_c_horizontal + sledPositionMM; + float a = config_st->payLoadPedalConfig_.lengthPedal_a; + float b = config_st->payLoadPedalConfig_.lengthPedal_b; + float c_ver = config_st->payLoadPedalConfig_.lengthPedal_c_vertical; + float c_hor = config_st->payLoadPedalConfig_.lengthPedal_c_horizontal + sledPositionMM; float c = sqrtf(c_ver * c_ver + c_hor * c_hor); //#define DEBUG_PEDAL_INCLINE @@ -61,8 +59,8 @@ float pedalInclineAngleDeg(float sledPositionMM, DAP_config_st& config_st) { // add incline due to AB incline --> result is incline realtive to horizontal if (abs(c_hor)>0.01) { - //alpha += atan(c_ver / c_hor); - alpha += atan2(c_ver, c_hor); // y, x + alpha += atan2f(c_ver, c_hor); // y, x + //alpha += atan2Fast(c_ver, c_hor); // y, x } @@ -80,7 +78,7 @@ float pedalInclineAngleDeg(float sledPositionMM, DAP_config_st& config_st) { -float convertToPedalForce(float F_l, float sledPositionMM, DAP_config_st& config_st) { +float convertToPedalForce(float F_l, float sledPositionMM, DAP_config_st * config_st) { // see https://de.wikipedia.org/wiki/Kosinussatz // A: is lower pedal pivot // B: is rear pedal pivot @@ -92,12 +90,12 @@ float convertToPedalForce(float F_l, float sledPositionMM, DAP_config_st& config // c: is sled line (connection AC) // d: is upper pedal plate (connection AC) - float a = config_st.payLoadPedalConfig_.lengthPedal_a; - float b = config_st.payLoadPedalConfig_.lengthPedal_b; - float d = config_st.payLoadPedalConfig_.lengthPedal_d; + float a = config_st->payLoadPedalConfig_.lengthPedal_a; + float b = config_st->payLoadPedalConfig_.lengthPedal_b; + float d = config_st->payLoadPedalConfig_.lengthPedal_d; - float c_ver = config_st.payLoadPedalConfig_.lengthPedal_c_vertical; - float c_hor = config_st.payLoadPedalConfig_.lengthPedal_c_horizontal + sledPositionMM; + float c_ver = config_st->payLoadPedalConfig_.lengthPedal_c_vertical; + float c_hor = config_st->payLoadPedalConfig_.lengthPedal_c_horizontal + sledPositionMM; float c = sqrtf(c_ver * c_ver + c_hor * c_hor); @@ -140,7 +138,7 @@ float convertToPedalForce(float F_l, float sledPositionMM, DAP_config_st& config // Calculate gradient of phi with respect to sled position. // This is done by taking the derivative of the force with respect to the sled position. -float convertToPedalForceGain(float sledPositionMM, DAP_config_st& config_st) { +float convertToPedalForceGain(float sledPositionMM, DAP_config_st * config_st) { // see https://de.wikipedia.org/wiki/Kosinussatz // A: is lower pedal pivot // B: is rear pedal pivot @@ -153,17 +151,18 @@ float convertToPedalForceGain(float sledPositionMM, DAP_config_st& config_st) { // c: is sled line (connection AC) // d: is upper pedal plate (connection AC) - float a = config_st.payLoadPedalConfig_.lengthPedal_a; - float b = config_st.payLoadPedalConfig_.lengthPedal_b; - float d = config_st.payLoadPedalConfig_.lengthPedal_d; + float a = config_st->payLoadPedalConfig_.lengthPedal_a; + float b = config_st->payLoadPedalConfig_.lengthPedal_b; + float d = config_st->payLoadPedalConfig_.lengthPedal_d; - float c_ver = config_st.payLoadPedalConfig_.lengthPedal_c_vertical; - float c_hor = config_st.payLoadPedalConfig_.lengthPedal_c_horizontal + sledPositionMM; + float c_ver = config_st->payLoadPedalConfig_.lengthPedal_c_vertical; + float c_hor = config_st->payLoadPedalConfig_.lengthPedal_c_horizontal + sledPositionMM; float c = sqrtf(c_ver * c_ver + c_hor * c_hor); float alpha = acos( (b*b + c*c - a*a) / (2*b*c) ); - float alphaPlus = atan2(c_ver, c_hor); // y, x + float alphaPlus = atan2f(c_ver, c_hor); // y, x + //float alphaPlus = atan2Fast(c_ver, c_hor); // y, x float sinAlpha = sin(alpha); float cosAlpha = cos(alpha); diff --git a/ESP32/src/SignalFilter.cpp b/ESP32/src/SignalFilter.cpp index 154e0915..009d3644 100644 --- a/ESP32/src/SignalFilter.cpp +++ b/ESP32/src/SignalFilter.cpp @@ -13,64 +13,168 @@ static const double KF_MODEL_NOISE_FORCE_ACCELERATION = ( 8.0f * 4.0f / 0.1f/ 0.1f ); +float position = 0; // Estimated position +float velocity = 0; // Estimated velocity +float dt = 0.1; // Time step (seconds) + +float P[2][2] = { // Initial error covariance + {1, 0}, + {0, 1} +}; +float F[2][2] = { // State transition matrix + {1, dt}, + {0, 1} +}; +float Q[2][2] = { // Process noise covariance + {0.1, 0.0}, + {0.0, 0.1} +}; +float H[1][2] = { // Measurement matrix + {1, 0} +}; +float R = 1; // Measurement noise covariance +float K[2]; // Kalman Gain +float z; // Measurement (position) +float y; // Measurement residual +float S; // Residual covariance + + + + + KalmanFilter::KalmanFilter(float varianceEstimate) : _timeLastObservation(micros()) { - // evolution matrix. Size is - _K.F = {(double)1.0, 0.0, - 0.0, (double)1.0}; + // // evolution matrix. Size is + // _K.F = {(double)1.0, 0.0, + // 0.0, (double)1.0}; - // command matrix. Size is - _K.B = {1.0, - 0.0}; + // // command matrix. Size is + // _K.B = {1.0, + // 0.0}; - // measurement matrix. Size is - _K.H = {1.0, 0.0}; + // // measurement matrix. Size is + // _K.H = {1.0, 0.0}; - // model covariance matrix. Size is - _K.Q = {1.0, 0.0, - 0.0, 1.0}; + // // model covariance matrix. Size is + // _K.Q = {1.0, 0.0, + // 0.0, 1.0}; - // measurement covariance matrix. Size is - _K.R = { varianceEstimate }; + // // measurement covariance matrix. Size is + // _K.R = { varianceEstimate }; } float KalmanFilter::filteredValue(float observation, float command, uint8_t modelNoiseScaling_u8) { + + // obtain time unsigned long currentTime = micros(); unsigned long elapsedTime = currentTime - _timeLastObservation; - double modelNoiseScaling_fl32 = modelNoiseScaling_u8; - modelNoiseScaling_fl32 /= 255.0; + float modelNoiseScaling_fl32 = modelNoiseScaling_u8; + modelNoiseScaling_fl32 /= 255.0f; + modelNoiseScaling_fl32 /= 1000.0f; + modelNoiseScaling_fl32 /= 20.0f; + + - if (modelNoiseScaling_fl32 < 0.001) + if (modelNoiseScaling_fl32 < 0.000001) { - modelNoiseScaling_fl32 = 0.001; + modelNoiseScaling_fl32 = 0.000001; } if (elapsedTime < 1) { elapsedTime=1; } _timeLastObservation = currentTime; - // update state transition and system covariance matrices - double delta_t = ((double)elapsedTime) / 1000000.0f;/// 1000000.0f; // convert to seconds - double delta_t_pow2 = delta_t * delta_t; - double delta_t_pow3 = delta_t_pow2 * delta_t; - double delta_t_pow4 = delta_t_pow2 * delta_t_pow2; - - _K.F = {(double)1.0, delta_t, - 0.0, (double)1.0}; + if (elapsedTime > 5000) { elapsedTime=5000; } + _timeLastObservation = currentTime; - _K.B = {1.0, - 0.0}; - double K_Q_11 = modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * (double)0.5f * delta_t_pow3; - _K.Q = {modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * (double)0.25f * delta_t_pow4, K_Q_11, - K_Q_11, modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * delta_t_pow2}; + // update state transition and system covariance matrices + //float delta_t = ((float)elapsedTime) / 1000000.0f;/// 1000000.0f; // convert to seconds + float delta_t = ((float)elapsedTime) / 1000.0f; + float delta_t_pow2 = delta_t * delta_t; + float delta_t_pow3 = delta_t_pow2 * delta_t; + float delta_t_pow4 = delta_t_pow2 * delta_t_pow2; + + // update transition matrix + F[0][1] = delta_t; + + float K_Q_11 = modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * (float)0.5f * delta_t_pow3; + Q[0][0] = modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * (float)0.25f * delta_t_pow4; + Q[0][1] = K_Q_11; + Q[1][0] = K_Q_11; + Q[1][1] = modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * delta_t_pow2; + + // Predict Step + float x_pred[2] = { + F[0][0] * position + F[0][1] * velocity, + F[1][0] * position + F[1][1] * velocity + }; + float P_pred[2][2] = { + {F[0][0] * P[0][0] + F[0][1] * P[1][0], F[0][0] * P[0][1] + F[0][1] * P[1][1]}, + {F[1][0] * P[0][0] + F[1][1] * P[1][0], F[1][0] * P[0][1] + F[1][1] * P[1][1]} + }; + + P_pred[0][0] += Q[0][0]; + P_pred[1][1] += Q[1][1]; + + // Update Step + z = observation; // Measurement + y = z - H[0][0] * x_pred[0]; // Residual + S = H[0][0] * P_pred[0][0] * H[0][0] + R; // Residual covariance + + K[0] = P_pred[0][0] * H[0][0] / S; // Kalman Gain + K[1] = P_pred[1][0] * H[0][0] / S; + + // Update state estimate + position = x_pred[0] + K[0] * y; + velocity = x_pred[1] + K[1] * y; + + // Update error covariance + P[0][0] = (1 - K[0] * H[0][0]) * P_pred[0][0]; + P[0][1] = (1 - K[0] * H[0][0]) * P_pred[0][1]; + P[1][0] = -K[1] * H[0][0] * P_pred[0][0] + P_pred[1][0]; + P[1][1] = -K[1] * H[0][0] * P_pred[0][1] + P_pred[1][1]; + + + return position; + + + // // obtain time + // unsigned long currentTime = micros(); + // unsigned long elapsedTime = currentTime - _timeLastObservation; + // double modelNoiseScaling_fl32 = modelNoiseScaling_u8; + // modelNoiseScaling_fl32 /= 255.0; + + // if (modelNoiseScaling_fl32 < 0.001) + // { + // modelNoiseScaling_fl32 = 0.001; + // } + // if (elapsedTime < 1) { elapsedTime=1; } + // _timeLastObservation = currentTime; + + // // update state transition and system covariance matrices + // double delta_t = ((double)elapsedTime) / 1000000.0f;/// 1000000.0f; // convert to seconds + // double delta_t_pow2 = delta_t * delta_t; + // double delta_t_pow3 = delta_t_pow2 * delta_t; + // double delta_t_pow4 = delta_t_pow2 * delta_t_pow2; + + // _K.F = {(double)1.0, delta_t, + // 0.0, (double)1.0}; + + // _K.B = {1.0, + // 0.0}; + + // double K_Q_11 = modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * (double)0.5f * delta_t_pow3; + // _K.Q = {modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * (double)0.25f * delta_t_pow4, K_Q_11, + // K_Q_11, modelNoiseScaling_fl32 * KF_MODEL_NOISE_FORCE_ACCELERATION * delta_t_pow2}; - // APPLY KALMAN FILTER - _K.update({observation}, {command}); - return _K.x(0,0); + // // APPLY KALMAN FILTER + // _K.update({observation}, {command}); + // return _K.x(0,0); } float KalmanFilter::changeVelocity() { - return _K.x(0,1) / 1.0f; + // return _K.x(0,1) / 1.0f; + return velocity * 1000.0f; } diff --git a/ESP32/src/StepperWithLimits.cpp b/ESP32/src/StepperWithLimits.cpp index d36dcaaf..ed07b23a 100644 --- a/ESP32/src/StepperWithLimits.cpp +++ b/ESP32/src/StepperWithLimits.cpp @@ -4,9 +4,9 @@ #include "Math.h" -#define STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT 20 -#define MIN_POS_MAX_ENDSTOP STEPS_PER_MOTOR_REVOLUTION * 3 // servo has to drive minimum N steps before it allows the detection of the max endstop - +#define STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT 50 +#define MIN_POS_MAX_ENDSTOP 10000 // servo has to drive minimum N steps before it allows the detection of the max endstop +#define INCLUDE_vTaskDelete 1 //uint32_t speed_in_hz = TICKS_PER_S / ticks; // TICKS_PER_S = 16000000L @@ -14,10 +14,27 @@ #define maxSpeedInTicks (TICKS_PER_S / MAXIMUM_STEPPER_SPEED) static const uint8_t LIMIT_TRIGGER_VALUE = LOW; // does endstop trigger high or low -static const int32_t ENDSTOP_MOVEMENT = (float)STEPS_PER_MOTOR_REVOLUTION / 100.0f; // how much to move between trigger checks +static const int32_t ENDSTOP_MOVEMENT = (float)100; // how much to move between trigger checks static const int32_t ENDSTOP_MOVEMENT_SENSORLESS = ENDSTOP_MOVEMENT * 5; + + +TaskHandle_t task_iSV_Communication; +unsigned long cycleTimeLastCall_lifelineCheck = 0;//micros(); +bool previousIsv57LifeSignal_b = true; +#define TIME_SINCE_SERVO_POS_CHANGE_TO_DETECT_STANDSTILL_IN_MS 200 +#define TIME_SINCE_SERVO_POS_CHANGE_TO_DETECT_CRASH_IN_MS 10000 +#define TWO_TO_THE_POWER_OF_15_MINUS_1 (uint32_t)32767 // 2^15 - 1 +//#define INT16_MAX (int32_t)65536 +static SemaphoreHandle_t semaphore_lifelineSignal = xSemaphoreCreateMutex(); +static SemaphoreHandle_t semaphore_resetServoPos = xSemaphoreCreateMutex(); +static SemaphoreHandle_t semaphore_readServoValues = xSemaphoreCreateMutex(); +static SemaphoreHandle_t semaphore_getSetCorrectedServoPos = xSemaphoreCreateMutex(); + + + + FastAccelStepperEngine& stepperEngine() { static FastAccelStepperEngine myEngine = FastAccelStepperEngine(); // this is a factory and manager for all stepper instances @@ -26,295 +43,950 @@ FastAccelStepperEngine& stepperEngine() { myEngine.init(); firstTime = false; } - + + myEngine.task_rate(2); return myEngine; } - -StepperWithLimits::StepperWithLimits(uint8_t pinStep, uint8_t pinDirection, uint8_t pinMin, uint8_t pinMax, bool invertMotorDir_b) - : _pinMin(pinMin), _pinMax(pinMax) - , _limitMin(0), _limitMax(0) +StepperWithLimits::StepperWithLimits(uint8_t pinStep, uint8_t pinDirection, bool invertMotorDir_b, uint32_t stepsPerMotorRev_arg_u32) + : _endstopLimitMin(0), _endstopLimitMax(0) , _posMin(0), _posMax(0) + , stepsPerMotorRev_u32(stepsPerMotorRev_arg_u32) + + { - pinMode(pinMin, INPUT); - pinMode(pinMax, INPUT); - - - _stepper = stepperEngine().stepperConnectToPin(pinStep); + // pinMode(pinMin, INPUT); + // pinMode(pinMax, INPUT); - + Serial.printf("InvertStepperDir: %d\n", invertMotorDir_b); + _stepper = stepperEngine().stepperConnectToPin(pinStep); - // Stepper Parameters - if (_stepper) { - _stepper->setDirectionPin(pinDirection, invertMotorDir_b); + _stepper->setDirectionPin(pinDirection, invertMotorDir_b); _stepper->setAutoEnable(true); _stepper->setAbsoluteSpeedLimit( maxSpeedInTicks ); // ticks _stepper->setSpeedInTicks( maxSpeedInTicks ); // ticks _stepper->setAcceleration(MAXIMUM_STEPPER_ACCELERATION); // steps/s² - _stepper->setForwardPlanningTimeInMs(8); + _stepper->setLinearAcceleration(0); + _stepper->setForwardPlanningTimeInMs(4); + //_stepper->setForwardPlanningTimeInMs(4); + + + /************************************************************/ + /* iSV57 initialization */ + /************************************************************/ + //delay(3000); + // find iSV57 servo ID + bool isv57slaveIdFound_b = isv57.findServosSlaveId(); + Serial.print("iSV57 slaveId found: "); + Serial.println( isv57slaveIdFound_b ); + + // restart ESP when no servo was detected + if (!isv57slaveIdFound_b) + { + Serial.println( "No servo found! Restarting ESP" ); + ESP.restart(); + } + + // check whether iSV57 is connected + // isv57LifeSignal_b = isv57.checkCommunication(); + setLifelineSignal(); + if (getLifelineSignal() == false) + { + Serial.println( "No lifeline detected! Restarting ESP" ); + ESP.restart(); + } + else + { + // read servos alarm history + isv57.readAlarmHistory(); + + // reset iSV57 alarms + bool servoAlarmsCleared = isv57.clearServoAlarms(); + + Serial.print("iSV57 communication state: "); + Serial.println( getLifelineSignal() ); + + + + // flash iSV57 registers + isv57.setupServoStateReading(); + invertMotorDir_global_b = invertMotorDir_b; + isv57.sendTunedServoParameters(invertMotorDir_global_b, stepsPerMotorRev_u32); + + + delay(30); + isv57.enableAxis(); + delay(100); + + // ToDo: + // - set servos internal rotation direction via debug port, thus ESPs and servos direction are aligned + + + // print all servo registers + /*if (dap_config_st.payLoadPedalConfig_.debug_flags_0 & DEBUG_INFO_0_PRINT_ALL_SERVO_REGISTERS) + { + isv57.readAllServoParameters(); + }*/ + + + // start read task + xTaskCreatePinnedToCore( + this->servoCommunicationTask, + "servoCommunicationTask", + 2000, + //STACK_SIZE_FOR_TASK_2, + this,//NULL, + 1, + &task_iSV_Communication, + 0); + + + + } + + + + + + + +} - //uint16_t tmp = _stepper->getMaxSpeedInTicks(); - //Serial.print("Max speed in Hz: "); - //Serial.println(tmp); -//#if defined(SUPPORT_ESP32_PULSE_COUNTER) -// _stepper->attachToPulseCounter(1, 0, 0); -//#endif - } +// Log all servo params +void StepperWithLimits::printAllServoParameters() +{ + logAllServoParams = true; } - -void StepperWithLimits::findMinMaxSensorless(isv57communication * isv57, DAP_config_st dap_config_st) +void StepperWithLimits::findMinMaxSensorless(DAP_config_st dap_config_st) { if (! hasValidStepper()) return; - // obtain servo states - isv57->readServoStates(); - bool endPosDetected = abs( isv57->servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; - - - int32_t setPosition = _stepper->getCurrentPosition(); - while(!endPosDetected){ - delay(10); - isv57->readServoStates(); - endPosDetected = abs( isv57->servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; - - setPosition = setPosition - ENDSTOP_MOVEMENT_SENSORLESS; - _stepper->moveTo(setPosition, true); - - //Serial.print("Min_DetValue: "); - //Serial.println(isv57->servo_current_percent); - } - - // move away from min position to reduce servos current reading - _stepper->forceStop(); - setPosition = setPosition + 5 * ENDSTOP_MOVEMENT_SENSORLESS; - _stepper->moveTo(setPosition, true); - _stepper->forceStopAndNewPosition(0); - _stepper->moveTo(0); - _limitMin = 0; - - // wait N ms to let the endPosDetected become 0 again - //delay(300); - - // read servo states again - //isv57->readServoStates(); - endPosDetected = 0;//abs( isv57->servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; - - setPosition = _stepper->getCurrentPosition(); - - // calculate max steps for endstop limit - float spindlePitch = max( dap_config_st.payLoadPedalConfig_.spindlePitch_mmPerRev_u8, (uint8_t)1 ); - float maxRevToReachEndPos = (float)dap_config_st.payLoadPedalConfig_.lengthPedal_travel / spindlePitch; - float maxStepsToReachEndPos = maxRevToReachEndPos * (float)STEPS_PER_MOTOR_REVOLUTION; - - Serial.print("Max travel steps: "); - Serial.println(maxStepsToReachEndPos); - - while (!endPosDetected) { - delay(10); - isv57->readServoStates(); - - // only trigger when difference is significant - if (setPosition > MIN_POS_MAX_ENDSTOP) - { - endPosDetected = abs( isv57->servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; - } - - // trigger endstop if configured max travel is reached - if (setPosition > maxStepsToReachEndPos) - { - endPosDetected = true; - } - - - setPosition = setPosition + ENDSTOP_MOVEMENT_SENSORLESS; - _stepper->moveTo(setPosition, true); - - //Serial.print("Max_DetValue: "); - //Serial.println(isv57->servo_current_percent); - } - - //_stepper->forceStop(); - //setPosition = setPosition - 5 * ENDSTOP_MOVEMENT; - - _limitMax = _stepper->getCurrentPosition(); + if ( getLifelineSignal() ) + { + + /************************************************************/ + /* servo reading check */ + /************************************************************/ + // check if servo readings are trustworthy, by checking if servos bus voltage is in reasonable range. Otherwise restart servo. + bool servoRadingsTrustworthy_b = false; + for (uint16_t waitTillServoCounterWasReset_Idx = 0; waitTillServoCounterWasReset_Idx < 10; waitTillServoCounterWasReset_Idx++) + { + delay(100); + + // voltage return is given in 0.1V units --> 10V range --> threshold 100 + // at beginning the values typically are initialized with -1 + float servosBusVoltageInVolt_fl32 = ( (float)getServosVoltage() ) / 10.0f; + servoRadingsTrustworthy_b = ( servosBusVoltageInVolt_fl32 >= 16) && ( servosBusVoltageInVolt_fl32 < 39); + + if (true == servoRadingsTrustworthy_b) + { + Serial.print("Servos bus voltage in expected range: "); + Serial.print( servosBusVoltageInVolt_fl32 ); + Serial.println("V"); + break; + } + } + + if(false == servoRadingsTrustworthy_b) + { + Serial.print("Servo bus voltage not in expected range (16V-39V). Restarting ESP!"); + ESP.restart(); + } + + + + + + + + + /************************************************************/ + /* min endstop detection */ + /************************************************************/ + bool endPosDetected = true; // abs( isv57.servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; + int32_t setPosition = 0; + + + // wait some time to check if signal stabilized + for (uint16_t tryIdx = 0; tryIdx < 500; tryIdx++) + { + delay(5); + endPosDetected = abs( getServosCurrent() ) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; + + if (false == endPosDetected) + { + break; + } + } + + // reduce speed and acceleration + _stepper->setSpeedInHz(MAXIMUM_STEPPER_SPEED / 10); + _stepper->setAcceleration(MAXIMUM_STEPPER_ACCELERATION / 10); + + // run continously in one direction until endstop is hit + //_stepper->keepRunningBackward(MAXIMUM_STEPPER_SPEED / 10); + _stepper->move(INT32_MIN, false); + + while( (!endPosDetected) && (getLifelineSignal()) ){ + delay(2); + endPosDetected = abs( getServosCurrent() ) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; + } + setPosition = - 5 * ENDSTOP_MOVEMENT_SENSORLESS; + delay(20); + _stepper->forceStopAndNewPosition(setPosition); + delay(100); + + Serial.println("Min endstop reached."); + Serial.printf("Current pos: %d\n", _stepper->getCurrentPosition() ); + // move slightly away from the block to prevent mechanical hits during normal operation + _stepper->moveTo(0, true); + _endstopLimitMin = 0; + //delay(1000); + + Serial.println("Moved to pos: 0"); + Serial.printf("Current pos: %d\n", _stepper->getCurrentPosition() ); + + + + + /************************************************************/ + /* reset servos internal position counter, */ + /* thus step loss recovery is simplified. */ + /************************************************************/ + // restart servo axis. This will reset the seros reg_add_position_given_p count to zero, thus equalizing the ESP zero and the servos zero position. + /*restartServo = true; + + bool servoAxisResetSuccessfull_b = false; + for (uint16_t waitTillServoCounterWasReset_Idx = 0; waitTillServoCounterWasReset_Idx < 10; waitTillServoCounterWasReset_Idx++) + { + delay(100); + + //bool servoPosRes_b = (50 > abs(isv57.servo_pos_given_p) ) || ( 50 > (INT16_MAX - abs(isv57.servo_pos_given_p)) ); + bool servoPosRes_b = 0 == (isv57.servo_pos_given_p); + if ( (false == restartServo) && (servoPosRes_b) ) + { + Serial.print("Servo axis was reset succesfully! Current position: "); + Serial.println(isv57.servo_pos_given_p); + servoAxisResetSuccessfull_b = true; + break; + } + } + + if(false == servoAxisResetSuccessfull_b) + { + Serial.print("Servo axis not reset. Restarting ESP!"); + ESP.restart(); + }*/ + + + // Serial.print("Servo axis current position (before clearing): "); + // Serial.println(isv57.servo_pos_given_p); + + // restartServo = true; + // delay(5000); + + // Serial.print("Servo axis current position (after clearing): "); + // Serial.println(isv57.servo_pos_given_p); + + + + + + + delay(200); + isv57.setZeroPos(); + // setMinPosition(); + + + /************************************************************/ + /* max endstop detection */ + /************************************************************/ + // calculate max steps for endstop limit + float spindlePitch = max( dap_config_st.payLoadPedalConfig_.spindlePitch_mmPerRev_u8, (uint8_t)1 ); + float maxRevToReachEndPos = (float)dap_config_st.payLoadPedalConfig_.lengthPedal_travel / spindlePitch; + float maxStepsToReachEndPos = maxRevToReachEndPos * (float)stepsPerMotorRev_u32; - // move slowly to min position - moveSlowlyToPos(_posMin); - - -#if defined(SUPPORT_ESP32_PULSE_COUNTER) - _stepper->clearPulseCounter(); -#endif - + endPosDetected = false; //abs( isv57.servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; + + // run continously in one direction until endstop is hit + //_stepper->keepRunningForward(MAXIMUM_STEPPER_SPEED / 10); + _stepper->move(INT32_MAX, false); + + // if endstop is reached, communication is lost or virtual endstop is hit + while( (!endPosDetected) && (getLifelineSignal()) ){ + delay(1); + if (_stepper->getCurrentPosition() > MIN_POS_MAX_ENDSTOP) + { + endPosDetected = abs( getServosCurrent() ) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; + } + + // virtual endstop + endPosDetected |= (_stepper->getCurrentPosition() > maxStepsToReachEndPos); + + //Serial.printf("Pos: %d\n", _stepper->getCurrentPosition()); + } + _stepper->forceStop(); + delay(100); + _endstopLimitMax = _stepper->getCurrentPosition() - 5 * ENDSTOP_MOVEMENT_SENSORLESS; + + Serial.printf("Max endstop reached: %d\n", _endstopLimitMax); + + // move slowly to min position + //moveSlowlyToPos(_posMin); + //moveSlowlyToPos(5*ENDSTOP_MOVEMENT_SENSORLESS); + moveSlowlyToPos(0); + + + // increase speed and accelerartion back to normal + //_stepper->setMaxSpeed(MAXIMUM_STEPPER_SPEED); + _stepper->setAcceleration(MAXIMUM_STEPPER_ACCELERATION); + _stepper->setSpeedInHz(MAXIMUM_STEPPER_SPEED); + } + } void StepperWithLimits::moveSlowlyToPos(int32_t targetPos_ui32) { // reduce speed and accelerartion + //_stepper->setMaxSpeed(MAXIMUM_STEPPER_SPEED / 4); _stepper->setSpeedInHz(MAXIMUM_STEPPER_SPEED / 4); - _stepper->setAcceleration(MAXIMUM_STEPPER_ACCELERATION / 4); // move to min _stepper->moveTo(targetPos_ui32, true); + // increase speed and accelerartion - _stepper->setAcceleration(MAXIMUM_STEPPER_ACCELERATION); + //_stepper->setMaxSpeed(MAXIMUM_STEPPER_SPEED); _stepper->setSpeedInHz(MAXIMUM_STEPPER_SPEED); } -void StepperWithLimits::findMinMaxEndstops() { - if (! hasValidStepper()) return; - int32_t setPosition = _stepper->getCurrentPosition(); - while(! (LIMIT_TRIGGER_VALUE == digitalRead(_pinMin))){ - setPosition = setPosition - ENDSTOP_MOVEMENT; - _stepper->moveTo(setPosition, true); - } - - _stepper->forceStopAndNewPosition(0); - _stepper->moveTo(0); - _limitMin = 0; - - setPosition = _stepper->getCurrentPosition(); - while(! (LIMIT_TRIGGER_VALUE == digitalRead(_pinMax))){ - setPosition = setPosition + ENDSTOP_MOVEMENT; - _stepper->moveTo(setPosition, true); - } +void StepperWithLimits::updatePedalMinMaxPos(uint8_t pedalStartPosPct, uint8_t pedalEndPosPct) { + int32_t limitRange = _endstopLimitMax - _endstopLimitMin; - _limitMax = _stepper->getCurrentPosition(); +// Serial.printf("PedalStart: %d, PedalEnd:%d\n", pedalStartPosPct, pedalEndPosPct); - _stepper->moveTo(_posMin, true); -#if defined(SUPPORT_ESP32_PULSE_COUNTER) - _stepper->clearPulseCounter(); -#endif + float helper; + helper = _endstopLimitMin + (((float)limitRange * (float)pedalStartPosPct) * 0.01f); + _posMin = (int32_t)helper; + + helper = _endstopLimitMin + (((float)limitRange * (float)pedalEndPosPct) * 0.01f); + _posMax = (int32_t)helper; } -void StepperWithLimits::updatePedalMinMaxPos(uint8_t pedalStartPosPct, uint8_t pedalEndPosPct) { - int32_t limitRange = _limitMax - _limitMin; - _posMin = _limitMin + ((limitRange * pedalStartPosPct) / 100); - _posMax = _limitMin + ((limitRange * pedalEndPosPct) / 100); + +void StepperWithLimits::forceStop() { + _stepper->forceStop(); } -void StepperWithLimits::refindMinLimit() { - int32_t setPosition = _stepper->getCurrentPosition(); - while(! (LIMIT_TRIGGER_VALUE == digitalRead(_pinMin))){ - setPosition = setPosition - ENDSTOP_MOVEMENT; - _stepper->moveTo(setPosition, true); - } - _stepper->forceStopAndNewPosition(_limitMin); +int8_t StepperWithLimits::moveTo(int32_t position, bool blocking) { + _stepper->moveTo(position, blocking); + + return 1; } -void StepperWithLimits::refindMinLimitSensorless(isv57communication * isv57) { +int32_t StepperWithLimits::getCurrentPositionFromMin() const { + return _stepper->getCurrentPosition() - _posMin; +} - // obtain servo states - isv57->readServoStates(); - bool endPosDetected = abs( isv57->servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; +int32_t StepperWithLimits::getMinPosition() const { + return _posMin; +} +// void StepperWithLimits::setMinPosition() { +// _posMin = getCurrentPosition(); +// } - int32_t setPosition = _stepper->getCurrentPosition(); - while(!endPosDetected){ - delay(10); - isv57->readServoStates(); - endPosDetected = abs( isv57->servo_current_percent) > STEPPER_WITH_LIMITS_SENSORLESS_CURRENT_THRESHOLD_IN_PERCENT; +int32_t StepperWithLimits::getCurrentPosition() const { + return _stepper->getCurrentPosition(); +} - setPosition = setPosition - ENDSTOP_MOVEMENT_SENSORLESS; - _stepper->moveTo(setPosition, true); +float StepperWithLimits::getCurrentPositionFraction() const { + return float(getCurrentPositionFromMin()) / getTravelSteps(); +} - //Serial.print("Min_DetValue: "); - //Serial.println(isv57->servo_current_percent); - } +float StepperWithLimits::getCurrentPositionFractionFromExternalPos(int32_t extPos_i32) const { + return ( (float)(extPos_i32))/ getTravelSteps(); +} - // move away from min position to reduce servos current reading - _stepper->forceStop(); - setPosition = setPosition + 5 * ENDSTOP_MOVEMENT_SENSORLESS; - _stepper->moveTo(setPosition, true); - _stepper->forceStopAndNewPosition(_limitMin); +int32_t StepperWithLimits::getTargetPositionSteps() const { + return _stepper->getPositionAfterCommandsCompleted(); } -void StepperWithLimits::checkLimitsAndResetIfNecessary() { - // in case the stepper loses its position and therefore an endstop is triggered reset position - if (LIMIT_TRIGGER_VALUE == digitalRead(_pinMin)) { - _stepper->forceStopAndNewPosition(_limitMin); - _stepper->moveTo(_posMin, true); - } - if (LIMIT_TRIGGER_VALUE == digitalRead(_pinMax)) { - _stepper->forceStopAndNewPosition(_limitMin); - _stepper->moveTo(_posMax, true); - } + + +void StepperWithLimits::setSpeed(uint32_t speedInStepsPerSecond) +{ + //_stepper->setMaxSpeed(speedInStepsPerSecond); // steps/s + _stepper->setSpeedInHz(MAXIMUM_STEPPER_SPEED); } -int8_t StepperWithLimits::moveTo(int32_t position, bool blocking) { - return _stepper->moveTo(position, blocking); +bool StepperWithLimits::isAtMinPos() +{ + + bool isNotRunning = !_stepper->isRunning(); + bool isAtMinPos = abs( getCurrentPositionFromMin() ) < 10; + + return isAtMinPos && isNotRunning; } -int32_t StepperWithLimits::getCurrentPositionFromMin() const { - return _stepper->getCurrentPosition() - _posMin; + + + +/************************************************************/ +/* Step loss recovery */ +/************************************************************/ +void StepperWithLimits::correctPos() +{ + if(semaphore_resetServoPos!=NULL) + { + // Take the semaphore and just update the config file, then release the semaphore + if(xSemaphoreTake(semaphore_resetServoPos, (TickType_t)1)==pdTRUE) + { + // tune the current servo position to compesnate the position offset + int32_t stepOffset =(int32_t)constrain(servo_offset_compensation_steps_i32, -10, 10); + + // if (stepOffset != 0) + // { + // Serial.print("Position compensation: "); + // Serial.print(servo_offset_compensation_steps_i32); + // Serial.print(", "); + // Serial.println(stepOffset); + // } + + // offset = ESPs position - servos position + // new ESP pos = ESPs position - offset = ESPs position - ESPs position + servos position = servos position + + _stepper->setCurrentPosition(_stepper->getCurrentPosition() - stepOffset); + servo_offset_compensation_steps_i32 = 0; // reset lost step variable to prevent overcompensation + xSemaphoreGive(semaphore_resetServoPos); + } + } + else + { + semaphore_resetServoPos = xSemaphoreCreateMutex(); + } } -int32_t StepperWithLimits::getCurrentPosition() const { - return _stepper->getCurrentPosition(); + + + + +/************************************************************/ +/* lifeline set and get */ +/************************************************************/ + +bool StepperWithLimits::getLifelineSignal() +{ + bool signal_b = false; + /*if(semaphore_lifelineSignal!=NULL) + { + + // Take the semaphore and just update the config file, then release the semaphore + if(xSemaphoreTake(semaphore_lifelineSignal, (TickType_t)1)==pdTRUE) + { + signal_b = isv57LifeSignal_b; + } + + } + else + { + semaphore_lifelineSignal = xSemaphoreCreateMutex(); + }*/ + + + signal_b = isv57LifeSignal_b; + + return signal_b; } +void StepperWithLimits::setLifelineSignal() +{ + + isv57LifeSignal_b = isv57.checkCommunication(); + + + /*if(semaphore_lifelineSignal!=NULL) + { + + // Take the semaphore and just update the config file, then release the semaphore + if(xSemaphoreTake(semaphore_lifelineSignal, (TickType_t)1)==pdTRUE) + { + isv57LifeSignal_b = isv57.checkCommunication(); + } -double StepperWithLimits::getCurrentPositionFraction() const { - return double(getCurrentPositionFromMin()) / getTravelSteps(); + } + else + { + semaphore_lifelineSignal = xSemaphoreCreateMutex(); + }*/ } -double StepperWithLimits::getCurrentPositionFractionFromExternalPos(int32_t extPos_i32) const { - return (double(extPos_i32) - _posMin)/ getTravelSteps(); + + + + + + + +int32_t StepperWithLimits::getServosVoltage() +{ + return isv57.servo_voltage_0p1V; } -int32_t StepperWithLimits::getTargetPositionSteps() const { - return _stepper->getPositionAfterCommandsCompleted(); +int32_t StepperWithLimits::getServosCurrent() +{ + return isv57.servo_current_percent; } +int32_t StepperWithLimits::getServosPos() +{ + //return isv57.servo_pos_given_p; + return isv57.getPosFromMin(); +} -void StepperWithLimits::printStates() + + +void StepperWithLimits::setServosInternalPositionCorrected(int32_t posCorrected_i32) { - int32_t currentStepperPos = _stepper->getCurrentPosition(); - int32_t currentStepperVel = _stepper->getCurrentSpeedInUs(); - int32_t currentStepperVel2 = _stepper->getCurrentSpeedInMilliHz(); + if(semaphore_getSetCorrectedServoPos!=NULL) + { + if(xSemaphoreTake(semaphore_getSetCorrectedServoPos, (TickType_t)1)==pdTRUE) { + servoPos_local_corrected_i32 = posCorrected_i32; + xSemaphoreGive(semaphore_getSetCorrectedServoPos); + } + } + else + { + semaphore_readServoValues = xSemaphoreCreateMutex(); + } - //Serial.println(currentStepperVel); - - int32_t currentStepperAccel = _stepper->getCurrentAcceleration(); +} - static RTDebugOutput rtDebugFilter({ "Pos", "Vel", "Vel2", "Accel"}); - rtDebugFilter.offerData({ currentStepperPos, currentStepperVel, currentStepperVel2, currentStepperAccel}); +int32_t StepperWithLimits::getServosInternalPositionCorrected() +{ + int32_t pos_i32 = 0; + if(semaphore_getSetCorrectedServoPos!=NULL) + { + if(xSemaphoreTake(semaphore_getSetCorrectedServoPos, (TickType_t)1)==pdTRUE) { + pos_i32 = servoPos_local_corrected_i32; + xSemaphoreGive(semaphore_getSetCorrectedServoPos); + } + } + else + { + semaphore_readServoValues = xSemaphoreCreateMutex(); + } + + return pos_i32; } -void StepperWithLimits::setSpeed(uint32_t speedInStepsPerSecond) + +int32_t StepperWithLimits::getServosInternalPosition() { - _stepper->setSpeedInHz(speedInStepsPerSecond); // steps/s + int32_t servoPos_local_i32 = 0; + + if(semaphore_readServoValues!=NULL) + { + if(xSemaphoreTake(semaphore_readServoValues, (TickType_t)1)==pdTRUE) { + servoPos_local_i32 = servoPos_i16; + xSemaphoreGive(semaphore_readServoValues); + } + } + else + { + semaphore_readServoValues = xSemaphoreCreateMutex(); + } + + return servoPos_local_i32; } -bool StepperWithLimits::isAtMinPos() + +void StepperWithLimits::configSteplossRecovAndCrashDetection(uint8_t flags_u8) { + enableSteplossRecov_b = (flags_u8 >> 0) & 1; + enableCrashDetection_b = (flags_u8 >> 1) & 1; +} - bool isNotRunning = !_stepper->isRunning(); - bool isAtMinPos = getCurrentPositionFromMin() == 0; +int64_t timeSinceLastServoPosChange_l = 0; +int64_t timeDiff = 0; +int16_t servoPos_last_i16 = 0; +int64_t timeNow_l = 0; - return isAtMinPos && isNotRunning; + +uint32_t stackSizeIdx_u32 = 0; + + + +int64_t timeNow_isv57SerialCommunicationTask_l = 0; +int64_t timePrevious_isv57SerialCommunicationTask_l = 0; +#define REPETITION_INTERVAL_ISV57_SERIALCOMMUNICATION_TASK (int64_t)10 + +void StepperWithLimits::servoCommunicationTask(void *pvParameters) +{ + + // Cast the parameter to StepperWithLimits pointer + StepperWithLimits* stepper_cl = static_cast(pvParameters); + + for(;;){ + + + + // measure callback time and continue, when desired period is reached + timeNow_isv57SerialCommunicationTask_l = millis(); + int64_t timeDiff_serialCommunicationTask_l = ( timePrevious_isv57SerialCommunicationTask_l + REPETITION_INTERVAL_ISV57_SERIALCOMMUNICATION_TASK) - timeNow_isv57SerialCommunicationTask_l; + uint32_t targetWaitTime_u32 = constrain(timeDiff_serialCommunicationTask_l, 0, REPETITION_INTERVAL_ISV57_SERIALCOMMUNICATION_TASK); + delay(targetWaitTime_u32); + timePrevious_isv57SerialCommunicationTask_l = millis(); + + + + + /************************************************************/ + /* recheck lifeline */ + /************************************************************/ + // check if servo communication is still there every N milliseconds + unsigned long now = millis(); + if ( (now - cycleTimeLastCall_lifelineCheck) > 500) + { + // if target cycle time is reached, update last time + cycleTimeLastCall_lifelineCheck = now; + stepper_cl->setLifelineSignal(); + } + + + /************************************************************/ + /* log all servo params */ + /************************************************************/ + if (true == stepper_cl->logAllServoParams) + { + stepper_cl->logAllServoParams = false; + stepper_cl->isv57.readAllServoParameters(); + } + + + + /************************************************************/ + /* read servo states */ + /* and calculate step loss */ + /************************************************************/ + if ( stepper_cl->getLifelineSignal() ) + { + + // restarting servo axis + if(true == stepper_cl->restartServo) + { + //stepper_cl->isv57.resetAxisCounter(); + + stepper_cl->isv57.disableAxis(); + delay(15); + stepper_cl->isv57.enableAxis(); + stepper_cl->restartServo = false; + delay(15); + } + + + // when servo has been restarted, the read states need to be initialized first + if (false == previousIsv57LifeSignal_b) + { + stepper_cl->isv57.setupServoStateReading(); + previousIsv57LifeSignal_b = true; + delay(50); + } + + + + + + + // read servo states + stepper_cl->isv57.readServoStates(); + + + if(semaphore_readServoValues!=NULL) + { + if(xSemaphoreTake(semaphore_readServoValues, (TickType_t)1)==pdTRUE) { + + // caclulate servos positions from endstop + //stepper_cl->servoPos_i16 = stepper_cl->isv57.servo_pos_given_p - stepper_cl->isv57.getZeroPos() ; + stepper_cl->servoPos_i16 = stepper_cl->isv57.getPosFromMin(); + + // in normal configuration, where servo is at front of the pedal, a positive servo rotation will make the sled move to the front. We want it to be the other way around though. Movement to the back means positive rotation + if (false == stepper_cl->invertMotorDir_global_b) + { + stepper_cl->servoPos_i16 *= -1; + } + + xSemaphoreGive(semaphore_readServoValues); + } + } + else + { + semaphore_readServoValues = xSemaphoreCreateMutex(); + } + + + + + // unwrap the servos position by aligning it to the ESPs position + int32_t servoPosCorrected_i32 = stepper_cl->getServosInternalPosition(); + int32_t espPos_i32 = stepper_cl->getCurrentPosition(); + // allow up to 50 wraps + // 1 rotation = 6400 steps + // 2^15 / 6400 = 5.12 rotations until wrap + // 5 rotations * 5mm/rotation * 50 wraps --> 250mm + for (uint8_t wrapIndex_u8 = 0; wrapIndex_u8 < 50; wrapIndex_u8++) + { + bool posCorrectedInLoop_b = false; + if ( ( espPos_i32 - servoPosCorrected_i32 ) > INT16_MAX ) + { + // 4294967296 = 2^16 + servoPosCorrected_i32 += 4294967296; + posCorrectedInLoop_b = true; + } + + if ( ( espPos_i32 - servoPosCorrected_i32 ) < INT16_MIN ) + { + // 4294967296 = 2^16 + servoPosCorrected_i32 -= 4294967296; + posCorrectedInLoop_b = true; + } + + if (false == posCorrectedInLoop_b) + { + break; + } + } + + + + stepper_cl->setServosInternalPositionCorrected(servoPosCorrected_i32); + + + + + + + int32_t servo_offset_compensation_steps_local_i32 = 0; + + // condition 1: servo must be at halt + // condition 2: the esp accel lib must be at halt + bool cond_stepperIsAtMinPos = false; + bool cond_timeSinceHitMinPositionLargerThanThreshold_1 = false; + bool cond_timeSinceHitMinPositionLargerThanThreshold_2 = false; + + // check whether target position from ESP hasn't changed and is at min endstop position + cond_stepperIsAtMinPos = stepper_cl->isAtMinPos(); + + + int16_t servoPos_now_i16; + if (cond_stepperIsAtMinPos == true) + { + //isv57.readServoStates(); + //int16_t servoPos_now_i16 = stepper_cl->isv57.servo_pos_given_p; + servoPos_now_i16 = stepper_cl->isv57.getPosFromMin(); + timeNow_l = millis(); + + // check whether servo position has changed, in case, update the halt detection variable + if (abs((int32_t)servoPos_last_i16 - (int32_t)servoPos_now_i16) > 30) + ///if (servoPos_last_i16 != servoPos_now_i16) + { + servoPos_last_i16 = servoPos_now_i16; + timeSinceLastServoPosChange_l = timeNow_l; + } + + // compute the time difference since last servo position change + timeDiff = timeNow_l - timeSinceLastServoPosChange_l; + + // if time between last servo position is larger than a threshold, detect servo standstill + if ( (timeDiff > TIME_SINCE_SERVO_POS_CHANGE_TO_DETECT_STANDSTILL_IN_MS) + && (timeNow_l > 0) ) + { + cond_timeSinceHitMinPositionLargerThanThreshold_1 = true; + } + else + { + cond_timeSinceHitMinPositionLargerThanThreshold_1 = false; + } + + + + // if time between last servo position is larger than a threshold, detect servo standstill. Longer intervall for crash detection + if ( (timeDiff > TIME_SINCE_SERVO_POS_CHANGE_TO_DETECT_CRASH_IN_MS) + && (timeNow_l > 0) ) + { + cond_timeSinceHitMinPositionLargerThanThreshold_2 = true; + } + else + { + cond_timeSinceHitMinPositionLargerThanThreshold_2 = false; + } + + + } + + + + + + + + + // Serial.printf("Cond1: %d, Cond2: %d, Cond3: %d, servoPos: %d\n", cond_stepperIsAtMinPos, cond_timeSinceHitMinPositionLargerThanThreshold_1, cond_timeSinceHitMinPositionLargerThanThreshold_2, servoPos_now_i16); + + // calculate zero position offset + + if (cond_stepperIsAtMinPos) + { + // When the servo turned off during driving, the servo loses its zero position and the correction might not be valid anymore. If still applied, the servo will somehow srive against the block + // resulting in excessive servo load --> current load. We'll detect whether min or max block was reached, depending on the position error sign + if (cond_timeSinceHitMinPositionLargerThanThreshold_2 && (true == stepper_cl->enableCrashDetection_b)) + { + + bool servoCurrentLow_b = abs(stepper_cl->isv57.servo_current_percent) < 50;//200; + if (!servoCurrentLow_b) + { + + // positive current means positive rotation + bool minBlockCrashDetected_b = false; + bool maxBlockCrashDetected_b = false; + if (stepper_cl->isv57.servo_current_percent > 0) // if current is positive, the rotation will be positive and thus the sled will move towards the user + { + minBlockCrashDetected_b = true; + stepper_cl->isv57.applyOfsetToZeroPos(-500); // bump up a bit to prevent the servo from pushing against the endstop continously + } + else + { + maxBlockCrashDetected_b = true; + stepper_cl->isv57.applyOfsetToZeroPos(500); // bump up a bit to prevent the servo from pushing against the endstop continously + } + + /*print_cycle_counter_u64++; + print_cycle_counter_u64 %= 10; + + if (print_cycle_counter_u64 == 0) + { + Serial.print("minDet: "); + Serial.print(minBlockCrashDetected_b); + + Serial.print("curr: "); + Serial.print(isv57.servo_current_percent); + + Serial.print("posError: "); + Serial.print(isv57.servo_pos_error_p); + + Serial.println(); + }*/ + + + //servo_offset_compensation_steps_local_i32 = isv57.servo_pos_error_p; + } + } + + + // step loss recovery + if (cond_timeSinceHitMinPositionLargerThanThreshold_1) + { + if (true == stepper_cl->enableSteplossRecov_b) + { + // calculate encoder offset + // movement to the back will reduce encoder value + + servo_offset_compensation_steps_local_i32 = espPos_i32 - servoPosCorrected_i32; + // if (false == stepper_cl->invertMotorDir_global_b) + // { + // servo_offset_compensation_steps_local_i32 *= -1; + // } + } + else + { + servo_offset_compensation_steps_local_i32 = 0; + } + + if(semaphore_resetServoPos!=NULL) + { + // Take the semaphore and just update the config file, then release the semaphore + if(xSemaphoreTake(semaphore_resetServoPos, (TickType_t)1)==pdTRUE) + { + stepper_cl->servo_offset_compensation_steps_i32 = servo_offset_compensation_steps_local_i32; + + + xSemaphoreGive(semaphore_resetServoPos); + } + } + else + { + semaphore_resetServoPos = xSemaphoreCreateMutex(); + } + } + + + + } + + + + + + #ifdef PRINT_TASK_FREE_STACKSIZE_IN_WORDS + if( stackSizeIdx_u32 == 1000) + { + UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL); + Serial.print("StackSize (Servo communication): "); + Serial.println(stackHighWaterMark); + stackSizeIdx_u32 = 0; + } + stackSizeIdx_u32++; + #endif + + + } + else + { + Serial.println("Servo communication lost!"); + delay(100); + previousIsv57LifeSignal_b = false; + } + + + } } -bool StepperWithLimits::correctPos(int32_t posOffset) + + +/*int32_t StepperWithLimits::getStepLossCompensation() { - // - int32_t stepOffset =(int32_t)constrain(posOffset, -10, 10); + if(semaphore_resetServoPos!=NULL) + { + + // Take the semaphore and just update the config file, then release the semaphore + if(xSemaphoreTake(semaphore_resetServoPos, (TickType_t)1)==pdTRUE) + { + servo_offset_compensation_steps_i32 = servo_offset_compensation_steps_local_i32; + xSemaphoreGive(semaphore_resetServoPos); + } + + } + else + { + semaphore_resetServoPos = xSemaphoreCreateMutex(); + //Serial.println("semaphore_resetServoPos == 0"); + } + + return servo_offset_compensation_steps_i32; +}*/ + + - // correct pos - _stepper->setCurrentPosition(_stepper->getCurrentPosition() + stepOffset); - return 1; -} diff --git a/ESP32/src/isv57communication.cpp b/ESP32/src/isv57communication.cpp index 3c4fdf2e..0ee61a67 100644 --- a/ESP32/src/isv57communication.cpp +++ b/ESP32/src/isv57communication.cpp @@ -7,7 +7,15 @@ Modbus modbus(Serial1); // initialize the communication isv57communication::isv57communication() { + + //Serial1.begin(38400, SERIAL_8N2, ISV57_RXPIN, ISV57_TXPIN, true); // Modbus serial + #if PCB_VERSION == 10 || PCB_VERSION == 9 + Serial1.begin(38400, SERIAL_8N1, ISV57_RXPIN, ISV57_TXPIN, false); // Modbus serial + #endif + #if PCB_VERSION != 10 && PCB_VERSION != 9 Serial1.begin(38400, SERIAL_8N1, ISV57_RXPIN, ISV57_TXPIN, true); // Modbus serial + #endif + modbus.init(MODE); } @@ -21,44 +29,111 @@ void isv57communication::setupServoStateReading() { // The iSV57 has four registers (0x0191, 0x0192, 0x0193, 0x0194) in which we can write, which values we want to obtain cyclicly // These registers can be obtained by sending e.g. the command: 0x63, 0x03, 0x0191, target_sate, CRC // tell the modbus slave, which registers will be read cyclicly - modbus.holdingRegisterWrite(slaveId, 0x0191, reg_add_position_given_p); - delay(50); - modbus.holdingRegisterWrite(slaveId, 0x0192, reg_add_velocity_current_feedback_percent); - delay(50); - modbus.holdingRegisterWrite(slaveId, 0x0193, reg_add_position_error_p); - delay(50); - modbus.holdingRegisterWrite(slaveId, 0x0194, reg_add_voltage_0p1V); - delay(50); - + modbus.checkAndReplaceParameter(slaveId, 0x0191, reg_add_position_given_p); + modbus.checkAndReplaceParameter(slaveId, 0x0192, reg_add_velocity_current_feedback_percent); + modbus.checkAndReplaceParameter(slaveId, 0x0193, reg_add_position_error_p); + modbus.checkAndReplaceParameter(slaveId, 0x0194, reg_add_voltage_0p1V); } void isv57communication::readAllServoParameters() { - for (uint16_t reg_sub_add_u16 = 0; reg_sub_add_u16 < pr_6_00; reg_sub_add_u16++) + for (uint16_t reg_sub_add_u16 = 0; reg_sub_add_u16 < (pr_7_00+49); reg_sub_add_u16++) { modbus.readParameter(slaveId, pr_0_00 + reg_sub_add_u16); } } +// Disable aixs command +void isv57communication::disableAxis() +{ + + Serial.println("Disabling servo"); + + // 0x3f, 0x06, 0x00, 0x85, 0x03, 0x03, 0xdc, 0x0c + //modbus.checkAndReplaceParameter(slaveId, 0x0085, 0x0303); + modbus.holdingRegisterWrite(slaveId, 0x0085, 0x0303); + // 0x3f, 0x06, 0x01, 0x39, 0x00, 0x00, 0x5c, 0xe5 + //modbus.checkAndReplaceParameter(slaveId, 0x0139, 0x0000); + modbus.holdingRegisterWrite(slaveId, 0x0139, 0x0008); + delay(30); + + // read routine + modbus.holdingRegisterRead(0x0085); + modbus.holdingRegisterRead(0x0139); + delay(5); +} + +void isv57communication::enableAxis() +{ + Serial.println("Enabling servo"); + + // 0x3f, 0x06, 0x00, 0x85, 0x03, 0x83, 0xdd, 0xac + // Pr4.08: 0x085 + modbus.holdingRegisterWrite(slaveId, 0x0085, 0x0383); + // 0x3f, 0x06, 0x01, 0x39, 0x00, 0x08, 0x5d, 0x23 + modbus.holdingRegisterWrite(slaveId, 0x0139, 0x0008); + delay(30); + + // read routine + modbus.holdingRegisterRead(0x0085); + modbus.holdingRegisterRead(0x0139); + delay(5); + + // modbus.holdingRegisterRead(0x0085); + // modbus.holdingRegisterRead(0x0139); + +} + + +// void isv57communication::resetAxisCounter() +// { +// Serial.println("Reset axis counter"); + +// modbus.holdingRegisterRead(0x0085); +// delay(10); +// modbus.holdingRegisterRead(0x0139); +// delay(10); + +// } + + + + + + + +void isv57communication::clearServoUnitPosition() +{ + // According to Leadshines User Manual of 2ELD2-RD DC Servo + // https://www.leadshine.com/upfiles/downloads/a3d7d12a120fd8e114f6288b6235ac1a_1690179981835.pdf + // Changing the position unit, will clear the position data + + modbus.checkAndReplaceParameter(slaveId, pr_5_00+20, 0); // encoder output resolution {0: Encoder units; 1: Command units; 2: 10000pulse/rotation} + delay(100); + modbus.checkAndReplaceParameter(slaveId, pr_5_00+20, 1); // encoder output resolution {0: Encoder units; 1: Command units; 2: 10000pulse/rotation} + delay(100); +} + // send tuned servo parameters -void isv57communication::sendTunedServoParameters() { +void isv57communication::sendTunedServoParameters(bool commandRotationDirection, uint32_t stepsPerMotorRev_u32) { bool retValue_b = false; // Pr0 register - retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+1, 0); // control mode + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+1, 0); // control mode # retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+2, 0); // deactivate auto gain retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+3, 10); // machine stiffness retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+4, 80); // ratio of inertia - retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+8, STEPS_PER_MOTOR_REVOLUTION); // microsteps + //retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+6, commandRotationDirection); // Command Pulse Rotational Direction + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+8, (long)stepsPerMotorRev_u32); // microsteps retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+9, 1); // 1st numerator retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+10, 1); // & denominator retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+13, 500); // 1st torque limit retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+14, 500); // position deviation setup - retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+16, 50); // regenerative braking resitor - retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+17, 50); + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+16, 500); // regenerative braking resitor + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+17, 500); retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+18, 0); // vibration suppression retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_0_00+19, 0); @@ -94,14 +169,19 @@ void isv57communication::sendTunedServoParameters() { retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+5, 20); retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+6, 99); retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+22, 0); - retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+23, 0); + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_2_00+23, 80);// FIR based command smoothing time. Since the stpper task runs every 4ms, this time is selected to be larger than that. Unit is 0.1ms + // Pr3 register retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_3_00+24, 5000); // maximum rpm - + // Pr5 register retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_5_00+13, 5000); // overspeed level - retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_5_00+20, 1); // encoder output resolution + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_5_00+20, 1); // encoder output resolution {0: Encoder units; 1: Command units; 2: 10000pulse/rotation} + + + //retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_5_00+32, 300); // command pulse input maximum setup + // Enable & tune reactive pumping. This will act like a braking resistor and reduce EMF voltage. // See https://en.wikipedia.org/wiki/Bleeder_resistor @@ -111,32 +191,94 @@ void isv57communication::sendTunedServoParameters() { retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_7_00+33, 1); // bleeder hysteresis voltage; Contrary to the manual this seems to be an offset voltage, thus Braking disabling voltage = Pr7.32 + Pr.33 + // retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_7_00+28, 1000); + // retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_7_00+29, 100); + + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_7_00+28, 1000); + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_7_00+29, 10); + + + //retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_5_00+33, 0); // pulse regenerative output limit setup [0,1] + // retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_6_00+37, 0); // oscillation detection level [0, 1000] 0.1% + + + // disable axis after servo startup --> ESP has to enable the axis first + // Pr4.08 + // long servoEnableStatus = modbus.holdingRegisterRead(slaveId, 0x03, pr_4_00+8); + // Serial.print("Servo enable setting: "); + // Serial.println(servoEnableStatus, HEX); + // delay(100); + // if (servoEnableStatus != 0x303) + // { + // isv57communication::disableAxis(); + // } + // delay(100); + // servoEnableStatus = modbus.holdingRegisterRead(slaveId, 0x03, pr_4_00+8); + // Serial.print("Servo enable setting: "); + // Serial.println(servoEnableStatus, HEX); + + // disable axis by default + retValue_b |= modbus.checkAndReplaceParameter(slaveId, pr_4_00+8, 0x0303); + + + // store the settings to servos NVM if necesssary if (retValue_b) { + // disable axis a second time, since the second signal must be send to. Don't know yet the meaning of that signal. + disableAxis(); + Serial.println("Servo registered in NVM have been updated! Please power cycle the servo and the ESP!"); + + // identified with logic analyzer. See \StepperParameterization\Meesages\StoreSettingsToEEPROM_0.png modbus.holdingRegisterWrite(slaveId, 0x019A, 0x5555); // store the settings to servos NVM + // ToDo: according to iSV57 manual, 0x2211 is the command to write values to EEPROM + delay(500); + + + // ToDo: soft reset servo. The iSV57 docu says Pr0.25: 0x6666 is soft reset + // modbus.holdingRegisterWrite(slaveId, 0x019A, 0x6666); // store the settings to servos NVM + + isv57_update_parameter_b=true; - delay(2000); + delay(1000); } + } bool isv57communication::findServosSlaveId() { bool slaveIdFound = false; - for (int slaveIdTest = 0; slaveIdTest<256; slaveIdTest++) + + // typically the servo address is 63, so start with that + int slaveIdTest = 63; + if(modbus.requestFrom(slaveIdTest, 0x03, 0x0000, 2) > 0) { - if(modbus.requestFrom(slaveIdTest, 0x03, 0x0000, 2) > 0) - { - slaveId = slaveIdTest; - slaveIdFound = true; - Serial.print("Found servo slave ID:"); - Serial.print(slaveId); - Serial.print("\r\n"); - break; - } + slaveId = slaveIdTest; + slaveIdFound = true; + Serial.print("Found servo slave ID:"); + Serial.print(slaveId); + Serial.print("\r\n"); } + + + if (false == slaveIdFound ) + { + for (int slaveIdTest = 0; slaveIdTest<256; slaveIdTest++) + { + if(modbus.requestFrom(slaveIdTest, 0x03, 0x0000, 2) > 0) + { + slaveId = slaveIdTest; + slaveIdFound = true; + Serial.print("Found servo slave ID:"); + Serial.print(slaveId); + Serial.print("\r\n"); + break; + } + } + } + return slaveIdFound; } @@ -174,10 +316,21 @@ int16_t isv57communication::getZeroPos() return zeroPos; } +int16_t isv57communication::getPosFromMin() +{ + return servo_pos_given_p - zeroPos; +} + // read servo states void isv57communication::readServoStates() { + // initialize with -1 to indicate non-trustworthyness + regArray[0] = -1; + regArray[1] = -1; + regArray[2] = -1; + regArray[3] = -1; + // read the four registers simultaneously int8_t numberOfRegistersToRead_u8 = 4; int bytesReceived_i = modbus.requestFrom(slaveId, 0x03, ref_cyclic_read_0, numberOfRegistersToRead_u8); @@ -188,13 +341,14 @@ void isv57communication::readServoStates() { { regArray[regIdx] = modbus.uint16(regIdx); } - - // write to public variables - servo_pos_given_p = regArray[0]; - servo_current_percent = regArray[1]; - servo_pos_error_p = regArray[2]; - servo_voltage_0p1V = regArray[3]; } + + // write to public variables + servo_pos_given_p = regArray[0]; + servo_current_percent = regArray[1]; + servo_pos_error_p = regArray[2]; + servo_voltage_0p1V = regArray[3]; + //Serial.print("Bytes :"); //Serial.println(bytesReceived_i); @@ -231,6 +385,9 @@ bool isv57communication::clearServoAlarms() { // clear alarm list modbus.holdingRegisterWrite(slaveId, 0x019a, 0x7777); + + + // ToDo: soft reset servo. The iSV57 docu says Pr0.25: 0x1111 resets current alarm; 0x1122 resets alarm history return 1; } @@ -248,40 +405,50 @@ bool isv57communication::readCurrentAlarm() { Serial.println( tmp, HEX); } } + + return 1; } bool isv57communication::readAlarmHistory() { -// -Serial.println("\niSV57 alarm history: "); -for (uint8_t idx=0; idx < 12; idx++) -{ - // example signal, read the 9th alarm - // 0x3f, 0x03, 0x12, 0x09, 0x00, 0x01, 0x55, 0xAE - - // read the four registers simultaneously - int bytesReceived_i = modbus.requestFrom(slaveId, 0x03, 0x1200 + idx, 1); - if(bytesReceived_i == (2)) - { - modbus.RxRaw(raw, len); - for (uint8_t regIdx = 0; regIdx < 1; regIdx++) - { - uint16_t tmp = modbus.uint16(regIdx) & 0x0FFF; // mask the first half byte as it does not contain info - - if (tmp > 0) - { - Serial.print("Alarm Idx: "); - Serial.print(idx); - Serial.print(", Alarm Code: "); - Serial.println( tmp, HEX); - } - - } - } -} - Serial.print("\n"); + // + Serial.println("\niSV57 alarm history: "); + for (uint8_t idx=0; idx < 12; idx++) + { + // example signal, read the 9th alarm + // 0x3f, 0x03, 0x12, 0x09, 0x00, 0x01, 0x55, 0xAE + + // read the four registers simultaneously + int bytesReceived_i = modbus.requestFrom(slaveId, 0x03, 0x1200 + idx, 1); + if(bytesReceived_i == (2)) + { + modbus.RxRaw(raw, len); + for (uint8_t regIdx = 0; regIdx < 1; regIdx++) + { + uint16_t tmp = modbus.uint16(regIdx) & 0x0FFF; // mask the first half byte as it does not contain info + + if (tmp > 0) + { + Serial.print("Alarm Idx: "); + Serial.print(idx); + Serial.print(", Alarm Code: "); + Serial.println( tmp, HEX); + } + + } + } + } + Serial.print("\n"); - return 1; + return 1; +} + +void isv57communication::resetToFactoryParams() +{ + // identified with logic analyzer. See \StepperParameterization\Meesages\ResetToFactorySettings_0.png + //modbus.holdingRegisterWrite(slaveId, 0x01F0, 0x0001); + // 0x3f, 0x03, 0x01, 0xF0, 0x00, 0x01, 0x81, 0x1B + modbus.holdingRegisterRead(0x01F0); } diff --git a/ESP32_master/include/DiyActivePedal_types.h b/ESP32_master/include/DiyActivePedal_types.h index 8d33dc11..0c9f7961 100644 --- a/ESP32_master/include/DiyActivePedal_types.h +++ b/ESP32_master/include/DiyActivePedal_types.h @@ -3,7 +3,7 @@ #include // define the payload revision -#define DAP_VERSION_CONFIG 141 +#define DAP_VERSION_CONFIG 142 // define the payload types #define DAP_PAYLOAD_TYPE_CONFIG 100 @@ -67,7 +67,7 @@ struct payloadPedalState_Extended { struct payloadBridgeState { uint8_t Pedal_RSSI; uint8_t Pedal_availability[3]; - uint8_t Bridge_action;//0=none, 1=enable pairing + uint8_t Bridge_action;//0=none, 1=enable pairing 2=Restart 3=download mode }; struct payloadPedalConfig { @@ -185,7 +185,7 @@ struct payloadPedalConfig { //OTA flag //uint8_t OTA_flag; - uint8_t enableReboot_u8; + uint8_t stepLossFunctionFlags_u8; //joystick out flag //uint8_t Joystick_ESPsync_to_ESP; }; diff --git a/ESP32_master/include/ESPNOW_lib.h b/ESP32_master/include/ESPNOW_lib.h index 8141f96d..bcea4575 100644 --- a/ESP32_master/include/ESPNOW_lib.h +++ b/ESP32_master/include/ESPNOW_lib.h @@ -24,6 +24,7 @@ bool ESPNow_update= false; bool ESPNow_no_device=false; bool update_basic_state=false; bool update_extend_state=false; +bool pedal_OTA_action_b=false; uint16_t Joystick_value[]={0,0,0}; bool ESPNow_request_config_b[3]={false,false,false}; bool ESPNow_error_b=false; @@ -146,7 +147,7 @@ void onRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) if(data_len==sizeof(myData)) { memcpy(&myData, data, sizeof(myData)); - pedal_status=myData.pedal_status; + //#ifdef ACTIVATE_JOYSTICK_OUTPUT // normalize controller output int32_t joystickNormalizedToInt32 = NormalizeControllerOutputValue(myData.controllerValue_i32, 0, 10000, 100); @@ -161,6 +162,7 @@ void onRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) { pedal_brake_value=joystickNormalizedToInt32; Joystick_value[1]=myData.controllerValue_i32; + pedal_status=myData.pedal_status;//control pedal status only by brake //joystick_update=true; } if(mac_addr[5]==Gas_mac[5]) @@ -248,16 +250,18 @@ void ESPNow_initialize() Serial.println("[L]Initializing ESPNow, please wait"); WiFi.macAddress(esp_Mac); Serial.printf("[L]Device Mac: %02X:%02X:%02X:%02X:%02X:%02X\n", esp_Mac[0], esp_Mac[1], esp_Mac[2], esp_Mac[3], esp_Mac[4], esp_Mac[5]); + //Serial.print("Current MAC Address: "); //Serial.println(WiFi.macAddress()); #ifndef ESPNow_Pairing_function + Serial.println("Overwriting Mac address......."); esp_wifi_set_mac(WIFI_IF_STA, &esp_Host[0]); delay(300); - Serial.print("Modified MAC Address: "); + Serial.print("[L]Modified MAC Address: "); Serial.println(WiFi.macAddress()); #endif ESPNow.init(); - Serial.println("Wait for ESPNOW"); + Serial.println("[L]Waiting for ESPNOW"); delay(3000); #ifdef Using_Board_ESP32 esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_MCS0_LGI); @@ -294,15 +298,30 @@ void ESPNow_initialize() { if(i==0) { - memcpy(&Clu_mac,&_ESP_pairing_reg.Pair_mac[i],6); + if(MacCheck(_ESP_pairing_reg.Pair_mac[0],_ESP_pairing_reg.Pair_mac[1])||MacCheck(_ESP_pairing_reg.Pair_mac[0],_ESP_pairing_reg.Pair_mac[2])) + { + Serial.println("[L]Clutch mac address is same with others, no clutch reading will apply"); + } + else + { + memcpy(&Clu_mac,&_ESP_pairing_reg.Pair_mac[i],6); + } + } if(i==1) { - memcpy(&Brk_mac,&_ESP_pairing_reg.Pair_mac[i],6); + memcpy(&Brk_mac,&_ESP_pairing_reg.Pair_mac[i],6); } if(i==2) { - memcpy(&Gas_mac,&_ESP_pairing_reg.Pair_mac[i],6); + if(MacCheck(_ESP_pairing_reg.Pair_mac[1],_ESP_pairing_reg.Pair_mac[2])) + { + Serial.println("[L]Throttle mac address is same with Brake, no Throttle reading will apply"); + } + else + { + memcpy(&Gas_mac,&_ESP_pairing_reg.Pair_mac[i],6); + } } if(i==3) { diff --git a/ESP32_master/include/FanatecInterface.h b/ESP32_master/include/FanatecInterface.h new file mode 100644 index 00000000..c7a332ef --- /dev/null +++ b/ESP32_master/include/FanatecInterface.h @@ -0,0 +1,69 @@ +// FanatecInterface.h + +#ifndef FANATEC_INTERFACE_H +#define FANATEC_INTERFACE_H + +#include +#include + +class FanatecInterface { +public: + // Constructor + FanatecInterface(int rxPin, int txPin, int plugPin); + + // Initialization function + void begin(); + + // Communication update function (to be called periodically in the loop) + void update(); + void communicationUpdate(); + + // Functions to set pedal values + void setThrottle(uint16_t value); + void setBrake(uint16_t value); + void setClutch(uint16_t value); + void setHandbrake(uint16_t value); + + // Function to set the connection callback + void onConnected(void (*callback)(bool)); + + // Check if connected to the Fanatec device + bool isConnected(); + bool isPlugged(); + +private: + // Internal helper functions + void performCommunicationSteps(); + void changeBaudRate(unsigned long baudrate); + void makeCRCTable(uint8_t poly); + uint8_t generateCRC(uint8_t* input, size_t length); + void createPacket(uint8_t* packet); + + // UART and plug pin settings + int _rxPin; + int _txPin; + int _plugPin; + + // HardwareSerial object + HardwareSerial* _serial; + + // CRC table + uint8_t _crcTable[256]; + + // Pedal values + uint16_t _throttle; + uint16_t _brake; + uint16_t _clutch; + uint16_t _handbrake; + + // Connection status + bool _connected; + + // Connection callback function pointer + void (*_connectedCallback)(bool); + + // Initialization flag + bool _initialized; +}; + +#endif // FANATEC_INTERFACE_H \ No newline at end of file diff --git a/ESP32_master/include/Main.h b/ESP32_master/include/Main.h index 868a8dbd..05d510a0 100644 --- a/ESP32_master/include/Main.h +++ b/ESP32_master/include/Main.h @@ -1,5 +1,4 @@ #pragma once - //#include /********************************************************************/ @@ -101,12 +100,62 @@ //#define BLUETOOTH_GAMEPAD //#define USB_JOYSTICK #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 1 - #define ESPNow_Pairing_function + //#define ESPNow_Pairing_function #define deviceID 98 #define Pairing_GPIO 0 #endif +// V3 version of dev PCB for ESP32 S3 +// flash instructions, see https://hutscape.com/tutorials/hello-arduino-esp32s3 +// 1. ESP32S3 Dev Module +// 2. USB CDC On Boot Enabled +#if PCB_VERSION == 5 + // ADC defines + #define PIN_DRDY 15//19// 19 --> DRDY + #define PIN_RST 6 // X --> X + #define PIN_SCK 16//16 // 16 -->SCLK + #define PIN_MISO 18 // 18 --> DOUT + #define PIN_MOSI 17 // 17 --> DIN + #define PIN_CS 7//21 // 21 --> CS + // stepper pins + #define dirPinStepper 37//22 + #define stepPinStepper 38//23 + + //analog output pin + //#define D_O 25 + //MCP4725 SDA SCL + #define MCP_SDA 4 + #define MCP_SCL 5 + + // endstop pins + #define minPin 12 + #define maxPin 13 + + // level shifter is present on this PCB design + #define SENSORLESS_HOMING true + #define ISV57_TXPIN 10//27 //17 + #define ISV57_RXPIN 9//26 // 16 + #define ESPNOW_Enable + #define Using_Board_ESP32S3 + //#define Using_MCP4728 + //#define Using_analog_output_ESP32_S3 + + //#define BLUETOOTH_GAMEPAD + #define USB_JOYSTICK + #define USING_LED + #define LED_ENABLE_WAVESHARE + #define LED_GPIO 38 + #define Pairing_GPIO 13 + #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 + //#define ESPNow_Pairing_function + #define deviceID 99 + #define Fanatec_comunication + #define Fanatec_serial_RX 18 + #define Fanatec_serial_TX 17 + #define Fanatec_plug 16 + #define OTA_Update +#endif @@ -148,12 +197,14 @@ //#define BLUETOOTH_GAMEPAD #define USB_JOYSTICK + #define USING_LED #define LED_ENABLE_WAVESHARE #define LED_GPIO 38 - #define Pairing_GPIO 0 + #define Pairing_GPIO 12 #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 - #define ESPNow_Pairing_function + //#define ESPNow_Pairing_function #define deviceID 99 + #define OTA_Update #endif #if PCB_VERSION == 7 @@ -190,11 +241,13 @@ //#define BLUETOOTH_GAMEPAD #define USB_JOYSTICK - #define LED_ENABLE_WAVESHARE - #define LED_GPIO 12 - #define Pairing_GPIO 34 + #define USING_LED + #define LED_ENABLE_DONGLE + #define LED_GPIO 39 + #define Pairing_GPIO 0 #define SERIAL_COOMUNICATION_TASK_DELAY_IN_MS 5 - #define ESPNow_Pairing_function + //#define ESPNow_Pairing_function #define deviceID 99 + #define OTA_Update #endif diff --git a/ESP32_master/include/OTA_Pull.h b/ESP32_master/include/OTA_Pull.h new file mode 100644 index 00000000..f3963dfa --- /dev/null +++ b/ESP32_master/include/OTA_Pull.h @@ -0,0 +1,138 @@ +#include +#include +#include + +#define JSON_URL_dev "https://raw.githubusercontent.com/gilphilbert/pedal-flasher/main/json/dev/Version_Bridge.json" +#define JSON_URL_main "https://raw.githubusercontent.com/gilphilbert/pedal-flasher/main/json/main/Version_Bridge.json" + + + + + +/* +#if PCB_VERSION==5 + #define JSON_URL_dev "https://raw.githubusercontent.com/tcfshcrw/FFBPedalOTA_Json/main/JSON/dev/Bridge/Version_Fanatec_bridge.json" + #define JSON_URL_main "https://raw.githubusercontent.com/tcfshcrw/FFBPedalOTA_Json/main/JSON/main/Bridge/Version_Fanatec_bridge.json" +#endif +#if PCB_VERSION==6 + #define JSON_URL_dev "https://raw.githubusercontent.com/tcfshcrw/FFBPedalOTA_Json/main/JSON/dev/Bridge/Version_devkit.json" + #define JSON_URL_main "https://raw.githubusercontent.com/tcfshcrw/FFBPedalOTA_Json/main/JSON/main/Bridge/Version_devkit.json" +#endif +#if PCB_VERSION==7 + #define JSON_URL_dev "https://raw.githubusercontent.com/tcfshcrw/FFBPedalOTA_Json/main/JSON/dev/Bridge/Version_Gilphilbert_dongle.json" + #define JSON_URL_main "https://raw.githubusercontent.com/tcfshcrw/FFBPedalOTA_Json/main/JSON/main/Bridge/Version_Gilphilbert_dongle.json" +#endif +*/ + +bool OTA_enable_b =false; +bool OTA_status =false; +struct Basic_WIfi_info +{ + uint8_t payloadType; + uint8_t device_ID; + uint8_t wifi_action; + uint8_t mode_select; + uint8_t SSID_Length; + uint8_t PASS_Length; + uint8_t WIFI_SSID[30]; + uint8_t WIFI_PASS[30]; +}; + +Basic_WIfi_info _basic_wifi_info; +char* SSID; +char* PASS; + +void wifi_initialized(char* Wifi_SSID, char* Wifi_PASS) +{ + Serial.print("[L]SSID: "); + Serial.print(Wifi_SSID); + Serial.print(" PASS: "); + Serial.println(Wifi_PASS); + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + delay(100); + //esp_wifi_set_max_tx_power(WIFI_POWER_8_5dBm); + WiFi.begin(Wifi_SSID, Wifi_PASS); + + // Display connection progress + Serial.print("[L]Connecting to WiFi:"); + Serial.print(WiFi.SSID()); + Serial.print(" "); + // Wait until WiFi is connected + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + // Print confirmation message when WiFi is connected + Serial.println("WiFi connected"); + Serial.print("[L]WiFi RSSI: "); + Serial.println(WiFi.RSSI()); + +} +void OTAcallback(int offset, int totallength); + +const char *errtext(int code) +{ + switch(code) + { + case ESP32OTAPull::UPDATE_AVAILABLE: + return "An update is available but wasn't installed"; + case ESP32OTAPull::NO_UPDATE_PROFILE_FOUND: + return "No profile matches"; + case ESP32OTAPull::NO_UPDATE_AVAILABLE: + return "Profile matched, but update not applicable"; + case ESP32OTAPull::UPDATE_OK: + return "An update was done, but no reboot"; + case ESP32OTAPull::HTTP_FAILED: + return "HTTP GET failure"; + case ESP32OTAPull::WRITE_ERROR: + return "Write error"; + case ESP32OTAPull::JSON_PROBLEM: + return "Invalid JSON"; + case ESP32OTAPull::OTA_UPDATE_FAIL: + return "Update fail (no OTA partition?)"; + default: + if (code > 0) + return "Unexpected HTTP response code"; + break; + } + return "Unknown error"; +} +/* +void DisplayInfo() +{ + char exampleImageURL[256]; + snprintf(exampleImageURL, sizeof(exampleImageURL), "https://example.com/Basic-OTA-Example-%s-%s.bin", ARDUINO_BOARD, VERSION); + + Serial.printf("Basic-OTA-Example v%s\n", VERSION); + Serial.printf("You need to post a JSON (text) file similar to this:\n"); + Serial.printf("{\n"); + Serial.printf(" \"Configurations\": [\n"); + Serial.printf(" {\n"); + Serial.printf(" \"Board\": \"%s\",\n", ARDUINO_BOARD); + Serial.printf(" \"Device\": \"%s\",\n", WiFi.macAddress().c_str()); + Serial.printf(" \"Version\": \"%s\",\n", VERSION); + Serial.printf(" \"URL\": \"%s\"\n", exampleImageURL); + Serial.printf(" }\n"); + Serial.printf(" ]\n"); + Serial.printf("}\n"); + Serial.printf("\n"); + Serial.printf("(Board, Device, Config, and Version are all *optional*.)\n"); + Serial.printf("\n"); + Serial.printf("Post the JSON at, e.g., %s\n", JSON_URL_main); + Serial.printf("Post the compiled bin at, e.g., %s\n\n", exampleImageURL); +} +*/ + +void OTAcallback(int offset, int totallength) +{ + Serial.print("[L]Updating: "); + Serial.print(offset); + Serial.print(" of "); + Serial.print(totallength); + Serial.print("("); + Serial.print(100 * offset / totallength); + Serial.println("%)"); + +} \ No newline at end of file diff --git a/ESP32_master/include/Version_Board.h b/ESP32_master/include/Version_Board.h new file mode 100644 index 00000000..316d205d --- /dev/null +++ b/ESP32_master/include/Version_Board.h @@ -0,0 +1,10 @@ +#define BRIDGE_FIRMWARE_VERSION "0.87.99" +#if PCB_VERSION==5 + #define BRIDGE_BOARD "Bridge_FANATEC" +#endif +#if PCB_VERSION==6 + #define BRIDGE_BOARD "DevKit" +#endif +#if PCB_VERSION==7 + #define BRIDGE_BOARD "Gilphilbert_Dongle" +#endif \ No newline at end of file diff --git a/ESP32_master/platformio.ini b/ESP32_master/platformio.ini index a47f2c75..fef9f8f8 100644 --- a/ESP32_master/platformio.ini +++ b/ESP32_master/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = esp32s3usbotg + [env] framework = arduino @@ -21,7 +21,12 @@ monitor_speed = 3000000 [common] lib_deps_external = - lemmingdev/ESP32-BLE-Gamepad @ ^0.5.5 + regenbogencode/ESPNowW@^1.0.2 + adafruit/Adafruit MCP4728@^1.0.9 + adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit NeoPixel@^1.12.3 + https://github.com/mikalhart/ESP32-OTA-Pull.git + bblanchon/ArduinoJson@^7.2.0 [env:esp32s3usbotg] board = esp32-s3-devkitc-1 @@ -43,67 +48,31 @@ board_upload.wait_for_upload_port = yes board_upload.require_upload_port = yes lib_deps = ${common.lib_deps_external} - schnoog/Joystick_ESP32S2 @ ^0.9.4 - adafruit/Adafruit MCP4725 @ ^2.0.2 - regenbogencode/ESPNowW@^1.0.2 - adafruit/Adafruit MCP4728@^1.0.9 - adafruit/Adafruit BusIO@^1.16.1 - https://github.com/Xylopyrographer/LiteLED.git - adafruit/Adafruit NeoPixel@^1.12.3 + + Joystick_ESP32S2=https://github.com/schnoog/Joystick_ESP32S2/archive/refs/heads/dev.zip + adafruit/Adafruit MCP4725@^2.0.2 [env:esp32] board = esp32dev lib_deps = ${common.lib_deps_external} - regenbogencode/ESPNowW@^1.0.2 - adafruit/Adafruit MCP4728@^1.0.9 - adafruit/Adafruit BusIO@^1.16.1 - adafruit/Adafruit NeoPixel@^1.12.3 + build_unflags = '-D PCB_VERSION=6' build_flags = '-D PCB_VERSION=3' -[env:esp32s3usbotg_FH4N2_CDC] -board = adafruit_feather_esp32s3 +[env:esp32s3-Fanatec] +board = esp32-s3-devkitc-1 board_build.f_cpu = 240000000L build_flags = - -DARDUINO_RUNNING_CORE=1 - -DCORE_DEBUG_LEVEL=1 + -DARDUINO_RUNNING_CORE=0 + -DCORE_DEBUG_LEVEL=0 -DARDUINO_USB_MODE=0 - -DARDUINO_USB_CDC_ON_BOOT=1 - -DARDUINO_USB_MSC_ON_BOOT=0 - -DARDUINO_USB_DFU_ON_BOOT=0 - -DPCB_VERSION=6 - '-DUSB_VID=0xF011' - '-DUSB_PID=0xF011' - '-DUSB_PRODUCT="DiyFfbPedal"' - '-DUSB_MANUFACTURER="OpenSource"' -board_upload.use_1200bps_touch = yes -board_upload.wait_for_upload_port = yes -board_upload.require_upload_port = yes -lib_deps = - ${common.lib_deps_external} - schnoog/Joystick_ESP32S2 @ ^0.9.4 - adafruit/Adafruit MCP4725 @ ^2.0.2 - regenbogencode/ESPNowW@^1.0.2 - adafruit/Adafruit MCP4728@^1.0.9 - adafruit/Adafruit BusIO@^1.16.1 - adafruit/Adafruit NeoPixel@^1.12.3 - -[env:esp32s3_FH4N2_SERIAL] -board = adafruit_feather_esp32s3 -board_build.f_cpu = 240000000L -build_unflags = - -DARDUINO_USB_CDC_ON_BOOT=1 -build_flags = - -DARDUINO_RUNNING_CORE=1 - -DCORE_DEBUG_LEVEL=1 - -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 - -DPCB_VERSION=6 + -DPCB_VERSION=5 '-DUSB_VID=0xF011' '-DUSB_PID=0xF011' '-DUSB_PRODUCT="DiyFfbPedal"' @@ -112,16 +81,13 @@ board_upload.use_1200bps_touch = yes board_upload.wait_for_upload_port = yes board_upload.require_upload_port = yes lib_deps = - ${common.lib_deps_external} - schnoog/Joystick_ESP32S2 @ ^0.9.4 - adafruit/Adafruit MCP4725 @ ^2.0.2 - regenbogencode/ESPNowW@^1.0.2 - adafruit/Adafruit MCP4728@^1.0.9 - adafruit/Adafruit BusIO@^1.16.1 - adafruit/Adafruit NeoPixel@^1.12.3 + ${common.lib_deps_external} + Joystick_ESP32S2=https://github.com/schnoog/Joystick_ESP32S2/archive/refs/heads/dev.zip + adafruit/Adafruit MCP4725@^2.0.2 + [env:esp32s3-gilphilbert] -board = adafruit_feather_esp32s3 +board = lolin_s3_mini board_build.f_cpu = 240000000L build_unflags = -DARDUINO_USB_CDC_ON_BOOT=1 @@ -141,11 +107,6 @@ board_upload.use_1200bps_touch = yes board_upload.wait_for_upload_port = yes board_upload.require_upload_port = yes lib_deps = - ${common.lib_deps_external} - schnoog/Joystick_ESP32S2 @ ^0.9.4 - adafruit/Adafruit MCP4725 @ ^2.0.2 - regenbogencode/ESPNowW@^1.0.2 - adafruit/Adafruit MCP4728@^1.0.9 - adafruit/Adafruit BusIO@^1.16.1 - https://github.com/Xylopyrographer/LiteLED.git - adafruit/Adafruit NeoPixel@^1.12.3 \ No newline at end of file + ${common.lib_deps_external} + Joystick_ESP32S2=https://github.com/schnoog/Joystick_ESP32S2/archive/refs/heads/dev.zip + adafruit/Adafruit MCP4725@^2.0.2 diff --git a/ESP32_master/src/Controller.cpp b/ESP32_master/src/Controller.cpp index c38b2ceb..c4880690 100644 --- a/ESP32_master/src/Controller.cpp +++ b/ESP32_master/src/Controller.cpp @@ -28,7 +28,7 @@ Joystick.setYAxisRange(JOYSTICK_MIN_VALUE, JOYSTICK_MAX_VALUE);//rudder brake brake Joystick.setZAxisRange(JOYSTICK_MIN_VALUE, JOYSTICK_MAX_VALUE);//rudder brake throttle delay(100); - + //Joystick.begin(); Joystick.begin(false); // rename HID device name, see e.g. https://github.com/schnoog/Joystick_ESP32S2/issues/8 diff --git a/ESP32_master/src/DiyActivePedal_types.cpp b/ESP32_master/src/DiyActivePedal_types.cpp index 775de287..54162a9f 100644 --- a/ESP32_master/src/DiyActivePedal_types.cpp +++ b/ESP32_master/src/DiyActivePedal_types.cpp @@ -99,7 +99,7 @@ void DAP_config_st::initialiseDefaults() { payLoadPedalConfig_.invertMotorDirection_u8 = 0; payLoadPedalConfig_.pedal_type=4; //payLoadPedalConfig_.OTA_flag=0; - payLoadPedalConfig_.enableReboot_u8=1; + payLoadPedalConfig_.stepLossFunctionFlags_u8=0b11; //payLoadPedalConfig_.Joystick_ESPsync_to_ESP=0; } diff --git a/ESP32_master/src/FanatecInterface.cpp b/ESP32_master/src/FanatecInterface.cpp new file mode 100644 index 00000000..215649c4 --- /dev/null +++ b/ESP32_master/src/FanatecInterface.cpp @@ -0,0 +1,245 @@ +// FanatecInterface.cpp + +#include "FanatecInterface.h" + +// Constructor +FanatecInterface::FanatecInterface(int rxPin, int txPin, int plugPin) + : _rxPin(rxPin), _txPin(txPin), _plugPin(plugPin), _serial(&Serial1), + _throttle(0), _brake(0), _clutch(0), _handbrake(0), + _connected(false), _connectedCallback(nullptr), _initialized(false) { +} + +// Initialization function +void FanatecInterface::begin() { + // Initialize serial port + _serial->begin(250000, SERIAL_8N1, _rxPin, _txPin); + pinMode(_plugPin, INPUT_PULLDOWN); + + // Generate CRC table + makeCRCTable(0x8C); +} + +// Communication update function (to be called periodically in the loop) +void FanatecInterface::communicationUpdate() { + bool detectState = isPlugged(); + if (!_initialized && detectState) { + performCommunicationSteps(); + if (!_initialized) { + // Call the connection callback if set + if (_connectedCallback) { + _connectedCallback(true); + } + } + _initialized = true; + _connected = true; + } + if (!detectState && _initialized) { + _initialized = false; + _connected = false; + if (_connectedCallback) { + _connectedCallback(false); + } + } +} + +void FanatecInterface::update() { + if (isPlugged()) { + // Create and send pedal data packet + uint8_t packet[12]; + createPacket(packet); + _serial->write(packet, 12); + } +} + +bool FanatecInterface::isPlugged() { + return digitalRead(_plugPin); +} + +// Functions to set pedal values +void FanatecInterface::setThrottle(uint16_t value) { + _throttle = value; +} + +void FanatecInterface::setBrake(uint16_t value) { + _brake = value; +} + +void FanatecInterface::setClutch(uint16_t value) { + _clutch = value; +} + +void FanatecInterface::setHandbrake(uint16_t value) { + _handbrake = value; +} + +// Function to set the connection callback +void FanatecInterface::onConnected(void (*callback)(bool)) { + _connectedCallback = callback; +} + +// Check if connected to the Fanatec device +bool FanatecInterface::isConnected() { + return _connected; +} + +// Internal helper functions + +void FanatecInterface::performCommunicationSteps() { + // Define communication steps + struct Step { + unsigned long baudRate; + const uint8_t* rxData; + size_t rxLength; + const uint8_t* txData; + size_t txLength; + }; + + // First step data + const uint8_t rxData1[] = {0x0A}; + const uint8_t txData1[] = {0x1A}; + + // Second step data + const uint8_t rxData2[] = {0x05}; + const uint8_t txData2[] = {0x15}; + + // Third step data (combined message) + const uint8_t rxData3[] = { + // First message + 0x7B, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x26, 0x7D, + // Second message + 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xAA, 0x7D, + // Third message + 0x7B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x7D + }; + const uint8_t txData3[] = { + // First message + 0x7B, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x26, 0x7D, + // Second message + 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xAA, 0x7D, + // Third message + 0x7B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x7D + }; + + Step steps[] = { + {250000, rxData1, sizeof(rxData1), txData1, sizeof(txData1)}, + {250000, rxData2, sizeof(rxData2), txData2, sizeof(txData2)}, + {115200, rxData3, sizeof(rxData3), txData3, sizeof(txData3)} + }; + + const int numSteps = sizeof(steps) / sizeof(steps[0]); + + int i = 0; + while (i < numSteps) { + changeBaudRate(steps[i].baudRate); + + delay(50); + + // Receive buffer + uint8_t rxBuffer[36]; + size_t rxIndex = 0; + unsigned long startTime = millis(); + + // Read expected number of bytes + while (rxIndex < steps[i].rxLength && (millis() - startTime) < 2000) { + if (_serial->available()) { + uint8_t receivedByte = _serial->read(); + rxBuffer[rxIndex++] = receivedByte; + } + } + + // Verify received data + if (rxIndex == steps[i].rxLength && memcmp(rxBuffer, steps[i].rxData, rxIndex) == 0) { + // Expected data received, send response + _serial->write(steps[i].txData, steps[i].txLength); + Serial.print("[L] "); + Serial.print("FANATEC Send Data step "); + Serial.print(i); + Serial.print(": "); + for (size_t j = 0; j < rxIndex; j++) { + Serial.print("0x"); + Serial.print(rxBuffer[j], HEX); + Serial.print(" "); + } + Serial.println(); + i++; // Move to next step + } else { + if (rxIndex > 0) { + Serial.print("[L] "); + Serial.print("FANATEC Received data in step "); + Serial.print(i); + Serial.print(": "); + for (size_t j = 0; j < rxIndex; j++) { + Serial.print("0x"); + Serial.print(rxBuffer[j], HEX); + Serial.print(" "); + } + Serial.print(" rxIndex "); + Serial.print(rxIndex); + Serial.println(" failed. Restarting from step 0."); + } + // Failure, restart from step 0 + i = 0; + } + } +} + +void FanatecInterface::changeBaudRate(unsigned long baudrate) { + _serial->updateBaudRate(baudrate); + _serial->flush(); + while (_serial->available()) { + _serial->read(); + } + delay(50); +} + +void FanatecInterface::makeCRCTable(uint8_t poly) { + for (int i = 0; i < 256; i++) { + uint8_t crc = i; + for (int j = 0; j < 8; j++) { + bool bit = (crc & 0x01) != 0; + crc >>= 1; + if (bit) { + crc ^= poly; + } + } + _crcTable[i] = crc; + } +} + +uint8_t FanatecInterface::generateCRC(uint8_t* input, size_t length) { + uint8_t crc = 0xFF; + for (size_t i = 0; i < length; i++) { + crc = _crcTable[input[i] ^ crc]; + } + return crc; +} + +void FanatecInterface::createPacket(uint8_t* packet) { + packet[0] = 0x7B; // Start byte + packet[1] = 0x01; // Command byte (send pedal data) + + // Add pedal data (little-endian) + packet[2] = _throttle & 0xFF; + packet[3] = (_throttle >> 8) & 0xFF; + + packet[4] = _brake & 0xFF; + packet[5] = (_brake >> 8) & 0xFF; + + packet[6] = _clutch & 0xFF; + packet[7] = (_clutch >> 8) & 0xFF; + + packet[8] = _handbrake & 0xFF; + packet[9] = (_handbrake >> 8) & 0xFF; + + // Calculate CRC + uint8_t crc = generateCRC(&packet[1], 9); // Exclude start byte for CRC + packet[10] = crc; + + packet[11] = 0x7D; // End byte +} \ No newline at end of file diff --git a/ESP32_master/src/Main.cpp b/ESP32_master/src/Main.cpp index 58e96b38..dfeebcc5 100644 --- a/ESP32_master/src/Main.cpp +++ b/ESP32_master/src/Main.cpp @@ -22,8 +22,11 @@ #include "Arduino.h" #include "Main.h" - - +#include "esp_system.h" +#include "soc/rtc_cntl_reg.h" +#include "FanatecInterface.h" +#include "OTA_Pull.h" +#include "Version_Board.h" //#define ALLOW_SYSTEM_IDENTIFICATION @@ -111,10 +114,17 @@ DAP_bridge_state_st dap_bridge_state_lcl;// #ifndef CONFIG_IDF_TARGET_ESP32S3 #include "soc/rtc_wdt.h" #endif -#ifdef LED_ENABLE_WAVESHARE +#ifdef USING_LED #include "soc/soc_caps.h" #include - #define LEDS_COUNT 1 + #ifdef LED_ENABLE_WAVESHARE + #define LEDS_COUNT 1 + Adafruit_NeoPixel pixels(LEDS_COUNT, LED_GPIO, NEO_RGB + NEO_KHZ800); + #endif + #ifdef LED_ENABLE_DONGLE + #define LEDS_COUNT 3 + Adafruit_NeoPixel pixels(LEDS_COUNT, LED_GPIO, NEO_GRB + NEO_KHZ800); + #endif #define CHANNEL 0 #define LED_BRIGHT 30 /* @@ -127,7 +137,7 @@ DAP_bridge_state_st dap_bridge_state_lcl;// static const crgb_t L_CYAN = 0x00ffff; static const crgb_t L_PURPLE = 0x800080; */ - Adafruit_NeoPixel pixels(LEDS_COUNT, LED_GPIO, NEO_RGB + NEO_KHZ800); + #endif @@ -142,6 +152,8 @@ TaskHandle_t Task1; TaskHandle_t Task2; TaskHandle_t Task3; TaskHandle_t Task4; +TaskHandle_t Task5; + //static SemaphoreHandle_t semaphore_updateConfig=NULL; bool configUpdateAvailable = false; // semaphore protected data DAP_config_st dap_config_st_local; @@ -209,6 +221,19 @@ void ESPNOW_SyncTask( void * pvParameters); void Joystick_Task( void * pvParameters); void LED_Task( void * pvParameters); void Serial_Task( void * pvParameters); +void LED_Task_Dongle( void * pvParameters); +void FanatecUpdate(void * pvParameters); + +#ifdef Fanatec_comunication + FanatecInterface fanatec(Fanatec_serial_RX, Fanatec_serial_TX, Fanatec_plug); // RX: GPIO18, TX: GPIO17, PLUG: GPIO16 + bool Fanatec_Mode=false; +#endif + +#ifdef OTA_Update + void OTATask( void * pvParameters ); + TaskHandle_t Task7; +#endif + /**********************************************************************************************/ /* */ /* setup function */ @@ -223,7 +248,7 @@ void setup() // - #if PCB_VERSION == 6 + #if PCB_VERSION == 5||PCB_VERSION == 6||PCB_VERSION == 7 //Serial.setTxTimeoutMs(0); Serial.setRxBufferSize(1024); Serial.setTimeout(5); @@ -247,7 +272,12 @@ void setup() Serial.println("[L]This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License."); Serial.println("[L]Please check github repo for more detail: https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal"); - + #ifdef OTA_Update + Serial.print("[L]Board:"); + Serial.println(BRIDGE_BOARD); + Serial.print("[L]Version:"); + Serial.println(BRIDGE_FIRMWARE_VERSION); + #endif // setup multi tasking /* @@ -257,9 +287,11 @@ void setup() semaphore_updatePedalStates = xSemaphoreCreateMutex(); */ delay(10); + #ifdef ESPNow_Pairing_function //button read setup pinMode(Pairing_GPIO, INPUT_PULLUP); EEPROM.begin(256); + #endif /* if(semaphore_updateJoystick==NULL) { @@ -373,8 +405,67 @@ void setup() 0); delay(500); #endif + #ifdef LED_ENABLE_DONGLE + pixels.begin(); + pixels.setBrightness(20); + pixels.setPixelColor(0,0xff,0xff,0xff); + pixels.show(); + xTaskCreatePinnedToCore( + LED_Task_Dongle, + "LED_update_Task", + 3000, + //STACK_SIZE_FOR_TASK_2, + NULL, + 1, + &Task3, + 0); + delay(500); + #endif + #ifdef Fanatec_comunication + // Initialize FanatecInterface + fanatec.begin(); + + // Set connection callback + fanatec.onConnected([](bool connected) { + if (connected) { + Serial.println("[L] FANATEC Connected to Wheelbase."); + } else { + Serial.println("[L] FANATEC Disconnected from Wheelbase."); + } + }); + delay(2000); + xTaskCreatePinnedToCore( + FanatecUpdate, + "Fanatec_update_Task", + 3000, + //STACK_SIZE_FOR_TASK_5, + NULL, + 1, + &Task5, + 1); + delay(500); + #endif + #ifdef OTA_Update + xTaskCreatePinnedToCore( + OTATask, + "OTA_update_Task", + 16000, + //STACK_SIZE_FOR_TASK_5, + NULL, + 1, + &Task7, + 1); + delay(500); + #endif Serial.println("[L]Setup end"); + //initialize wifi + for(uint i=0;i<30;i++) + { + _basic_wifi_info.WIFI_PASS[i]=0; + _basic_wifi_info.WIFI_SSID[i]=0; + } + } @@ -402,7 +493,6 @@ bool building_dap_esppairing_lcl =false; void loop() { taskYIELD(); - //delay(2); } void ESPNOW_SyncTask( void * pvParameters ) @@ -446,7 +536,7 @@ void ESPNOW_SyncTask( void * pvParameters ) //timeout check if(now-Pairing_state_start>Pairing_timeout) { - Serial.println("[L]Reach timeout"); + Serial.println("[L]Bridge Pairing timeout!"); ESPNow_pairing_action_b=false; LED_Status=0; if(UpdatePairingToEeprom) @@ -466,9 +556,12 @@ void ESPNOW_SyncTask( void * pvParameters ) Serial.print(i); Serial.print("Pair: "); Serial.print(ESP_pairing_reg_local.Pair_status[i]); - Serial.printf(" Mac: %02X:%02X:%02X:%02X:%02X:%02X\n", ESP_pairing_reg_local.Pair_mac[i][0], ESP_pairing_reg_local.Pair_mac[i][1], ESP_pairing_reg_local.Pair_mac[i][2], ESP_pairing_reg_local.Pair_mac[i][3], ESP_pairing_reg_local.Pair_mac[i][4], ESP_pairing_reg_local.Pair_mac[i][5]); + Serial.printf(" Mac: %02X:%02X:%02X:%02X:%02X:%02X", ESP_pairing_reg_local.Pair_mac[i][0], ESP_pairing_reg_local.Pair_mac[i][1], ESP_pairing_reg_local.Pair_mac[i][2], ESP_pairing_reg_local.Pair_mac[i][3], ESP_pairing_reg_local.Pair_mac[i][4], ESP_pairing_reg_local.Pair_mac[i][5]); + Serial.println(""); } + Serial.println(""); } + Serial.println(""); //adding peer /* for(int i=0; i<4;i++) @@ -573,6 +666,26 @@ void ESPNOW_SyncTask( void * pvParameters ) //Serial.println("Broadcast sent"); dap_action_update=false; } + //forward the basic wifi info for pedals + if(pedal_OTA_action_b) + { + switch(_basic_wifi_info.device_ID) + { + case 0: + ESPNow.send_message(Clu_mac,(uint8_t *) &_basic_wifi_info,sizeof(Basic_WIfi_info)); + Serial.println("[L]Forward to Clutch"); + break; + case 1: + ESPNow.send_message(Brk_mac,(uint8_t *) &_basic_wifi_info,sizeof(Basic_WIfi_info)); + Serial.println("[L]Forward to Brake"); + break; + case 2: + ESPNow.send_message(Gas_mac,(uint8_t *) &_basic_wifi_info,sizeof(Basic_WIfi_info)); + Serial.println("[L]Forward to Throttle"); + break; + } + pedal_OTA_action_b=false; + } delay(2); } @@ -594,6 +707,8 @@ void Serial_Task( void * pvParameters) bool structChecker = true; if (n > 0) { + //Serial.print("[L]get size:"); + //Serial.println(n); switch (n) { case sizeof(DAP_actions_st) : @@ -709,12 +824,83 @@ void Serial_Task( void * pvParameters) { if(dap_bridge_state_lcl.payloadBridgeState_.Bridge_action==1) { - Serial.println("[L]Get Pair action"); - software_pairing_action_b=true; + #ifdef ESPNow_Pairing_function + Serial.println("[L]Bridge Pairing..."); + software_pairing_action_b=true; + #endif + #ifndef ESPNow_Pairing_function + Serial.println("[L]Pairing command didn't supported"); + #endif } + //action=2, restart + if(dap_bridge_state_lcl.payloadBridgeState_.Bridge_action==2) + { + Serial.println("[L]Bridge Restart"); + delay(1000); + ESP.restart(); + } + if(dap_bridge_state_lcl.payloadBridgeState_.Bridge_action==3) + { + //aciton=3 restart into boot mode + #ifdef Using_Board_ESP32S3 + Serial.println("[L]Bridge Restart into Download mode"); + delay(1000); + REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + ESP.restart(); + #endif + #ifdef Using_Board_ESP32 + Serial.println("[L]Command not supported "); + delay(1000); + #endif + + } + + } break; + case sizeof(Basic_WIfi_info) : + Serial.println("[L]get basic wifi info"); + Serial.readBytes((char*)&_basic_wifi_info, sizeof(Basic_WIfi_info)); + #ifdef OTA_Update + if(_basic_wifi_info.device_ID==deviceID) + { + SSID=new char[_basic_wifi_info.SSID_Length+1]; + PASS=new char[_basic_wifi_info.PASS_Length+1]; + memcpy(SSID,_basic_wifi_info.WIFI_SSID,_basic_wifi_info.SSID_Length); + memcpy(PASS,_basic_wifi_info.WIFI_PASS,_basic_wifi_info.PASS_Length); + SSID[_basic_wifi_info.SSID_Length]=0; + PASS[_basic_wifi_info.PASS_Length]=0; + /* + Serial.print("[L]SSID(uint)="); + for(uint i=0; i<_basic_wifi_info.SSID_Length;i++) + { + Serial.print(_basic_wifi_info.WIFI_SSID[i]); + Serial.print(","); + } + Serial.println(" "); + Serial.print("[L]PASS(uint)="); + for(uint i=0; i<_basic_wifi_info.PASS_Length;i++) + { + Serial.print(_basic_wifi_info.WIFI_PASS[i]); + Serial.print(","); + } + Serial.println(" "); + + Serial.print("[L]SSID="); + Serial.println(SSID); + Serial.print("[L]PASS="); + Serial.println(PASS); + */ + OTA_enable_b=true; + } + else + { + pedal_OTA_action_b=true; + } + #endif + + break; default: // flush the input buffer while (Serial.available()) @@ -938,6 +1124,105 @@ void Joystick_Task( void * pvParameters ) } } +//OTA multitask +uint16_t OTA_count=0; +bool message_out_b=false; +bool OTA_enable_start=false; +uint32_t otaTask_stackSizeIdx_u32 = 0; +void OTATask( void * pvParameters ) +{ + + for(;;) + { + #ifdef OTA_Update + if(OTA_count>200) + { + message_out_b=true; + OTA_count=0; + } + else + { + OTA_count++; + } + + + if(OTA_enable_b) + { + if(message_out_b) + { + message_out_b=false; + Serial1.println("[L]OTA enable flag on"); + } + if(OTA_status) + { + + //server.handleClient(); + } + else + { + Serial.println("[L]de-initialize espnow"); + Serial.println("[L]wait..."); + esp_err_t result= esp_now_deinit(); + ESPNow_initial_status=false; + ESPNOW_status=false; + delay(200); + if(result==ESP_OK) + { + OTA_status=true; + delay(1000); + //ota_wifi_initialize(APhost); + wifi_initialized(SSID,PASS); + delay(2000); + ESP32OTAPull ota; + char* Version_tag; + int ret; + ota.SetCallback(OTAcallback); + ota.OverrideBoard(BRIDGE_BOARD); + Version_tag=BRIDGE_FIRMWARE_VERSION; + if(_basic_wifi_info.wifi_action==1) + { + Version_tag="0.0.0"; + Serial.println("Force update"); + } + switch (_basic_wifi_info.mode_select) + { + case 1: + Serial.printf("[L]Flashing to latest Main, checking %s to see if an update is available...\n", JSON_URL_main); + ret = ota.CheckForOTAUpdate(JSON_URL_main, Version_tag); + Serial.printf("[L]CheckForOTAUpdate returned %d (%s)\n\n", ret, errtext(ret)); + break; + case 2: + Serial.printf("[L]Flashing to latest Dev, checking %s to see if an update is available...\n", JSON_URL_dev); + ret = ota.CheckForOTAUpdate(JSON_URL_dev, Version_tag); + Serial.printf("[L]CheckForOTAUpdate returned %d (%s)\n\n", ret, errtext(ret)); + break; + default: + break; + } + + delay(3000); + } + + } + } + + //delay(2); + #endif + + #ifdef PRINT_TASK_FREE_STACKSIZE_IN_WORDS + if( otaTask_stackSizeIdx_u32 == 1000) + { + UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL); + Serial.print("StackSize (OTA): "); + Serial.println(stackHighWaterMark); + otaTask_stackSizeIdx_u32 = 0; + } + otaTask_stackSizeIdx_u32++; + #endif + delay(2); + } +} + //LED task uint8_t LED_bright_index=0; uint8_t LED_bright_direction=1; @@ -1019,6 +1304,97 @@ void LED_Task( void * pvParameters) } } +void LED_Task_Dongle( void * pvParameters) +{ + for(;;) + { + #ifdef LED_ENABLE_DONGLE + //LED status update + if(LED_Status==0) + { + if(LED_bright_index>30) + { + LED_bright_direction=-1; + } + if(LED_bright_index<2) + { + LED_bright_direction=1; + } + LED_bright_index=LED_bright_index+LED_bright_direction; + pixels.setBrightness(LED_bright_index); + + for(uint i=0;i<3;i++) + { + if(dap_bridge_state_st.payloadBridgeState_.Pedal_availability[i]==1) + { + pixels.setPixelColor(i,0xff,0x0f,0x00);//Orange + } + else + { + pixels.setPixelColor(i,0xff,0xff,0xff);//White + } + } + pixels.show(); + + delay(150); + } + if(LED_Status==1)//pairing + { + + //delay(1000); + for(uint i=0;i<3;i++) + { + pixels.setPixelColor(i,0xff,0x00,0x00);//Red + } + + pixels.setBrightness(25); + pixels.show(); + delay(500); + for(uint i=0;i<3;i++) + { + pixels.setPixelColor(i,0x00,0x00,0x00);//fill no color + } + + //pixels.setBrightness(0); + pixels.show(); + delay(500); + } + + #endif + delay(10); + } +} + + +void FanatecUpdate(void * pvParameters) +{ + for(;;) + { + #ifdef Fanatec_comunication + fanatec.communicationUpdate(); + if (fanatec.isPlugged()) { + uint16_t throttleValue = pedal_throttle_value; + uint16_t brakeValue = pedal_brake_value; + uint16_t clutchValue = pedal_cluth_value; + uint16_t handbrakeValue = 0; // Set if needed + + // Pedal input values to 0 - 10000 + throttleValue = map(throttleValue, 0, 10000, 0, 65535); + brakeValue = map(brakeValue, 0, 10000, 0, 22000); + clutchValue = map(clutchValue, 0, 10000, 0, 65535); + + // Set pedal values in FanatecInterface + fanatec.setThrottle(throttleValue); + fanatec.setBrake(brakeValue); + fanatec.setClutch(clutchValue); + fanatec.setHandbrake(handbrakeValue); + + fanatec.update(); + } + #endif + delay(10); + } +} /**********************************************************************************************/ /* */ diff --git a/Helper/bins/esp32s3_Bridge_Fanatec/boot_app0.bin b/Helper/bins/esp32s3_Bridge_Fanatec/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/Helper/bins/esp32s3_Bridge_Fanatec/boot_app0.bin differ diff --git a/Helper/obtainVersionString.py b/Helper/obtainVersionString.py new file mode 100644 index 00000000..a9abf91b --- /dev/null +++ b/Helper/obtainVersionString.py @@ -0,0 +1,55 @@ +import requests +import re + +# URL to get releases from the GitHub repository +repo_url = "https://api.github.com/repos/ChrGri/DIY-Sim-Racing-FFB-Pedal/releases" + +# Send a GET request to the GitHub API through the proxy +response = requests.get(repo_url) + +# Prepare the output message +output_message = "" + +# Check if the request was successful (status code 200) +if response.status_code == 200: + releases = response.json() # Parse the JSON response + + # Filter for non-prerelease versions (i.e., where "prerelease" is False) + non_prerelease_releases = [release for release in releases if not release['prerelease']] + + if non_prerelease_releases: + # Sort the non-prerelease releases by their "created_at" field (in descending order) + sorted_releases = sorted(non_prerelease_releases, key=lambda x: x['created_at'], reverse=True) + + # The first release in the sorted list will be the most recent non-prerelease + latest_release = sorted_releases[0] + version_number = latest_release['tag_name'][17:] # The tag name is usually the version number + + tag_name = latest_release['tag_name'] + # Use regex to extract the number after the last underscore + match = re.search(r'Release_Package_v(\d+)', tag_name) + if match: + version_number = float(match.group(1)) # Convert the extracted version to an integer + new_version_number = version_number + .1 # Increment the version number by 1 + #output_message = f"xyz_v{new_version_number}" + output_message = str(new_version_number) + else: + output_message = "0" + + + #output_message = f"The version number of the latest non-prerelease release is: {version_number}" + #output_message = str( float(version_number) + 0.1 ) # increment the version number + else: + output_message = "No non-prerelease releases found." +else: + output_message = f"Failed to fetch releases. HTTP Status Code: {response.status_code}" + +# Write the result to a file +file_path = "expectedVersion.txt" + +with open(file_path, "w") as file: + file.write(output_message) + +print(f"Output written to {file_path}") + +print("Version is: " + output_message) diff --git a/OTA/Bridge/Fanatec_Bridge/boot_app0.bin b/OTA/Bridge/Fanatec_Bridge/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/Bridge/Fanatec_Bridge/boot_app0.bin differ diff --git a/OTA/Bridge/Fanatec_Bridge/bootloader.bin b/OTA/Bridge/Fanatec_Bridge/bootloader.bin new file mode 100644 index 00000000..204061ac Binary files /dev/null and b/OTA/Bridge/Fanatec_Bridge/bootloader.bin differ diff --git a/OTA/Bridge/Fanatec_Bridge/firmware.bin b/OTA/Bridge/Fanatec_Bridge/firmware.bin new file mode 100644 index 00000000..5e852311 Binary files /dev/null and b/OTA/Bridge/Fanatec_Bridge/firmware.bin differ diff --git a/OTA/Bridge/Fanatec_Bridge/partitions.bin b/OTA/Bridge/Fanatec_Bridge/partitions.bin new file mode 100644 index 00000000..951265fe Binary files /dev/null and b/OTA/Bridge/Fanatec_Bridge/partitions.bin differ diff --git a/OTA/Bridge/Gilphilbert_dongle/boot_app0.bin b/OTA/Bridge/Gilphilbert_dongle/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/Bridge/Gilphilbert_dongle/boot_app0.bin differ diff --git a/OTA/Bridge/Gilphilbert_dongle/bootloader.bin b/OTA/Bridge/Gilphilbert_dongle/bootloader.bin new file mode 100644 index 00000000..f0633e8d Binary files /dev/null and b/OTA/Bridge/Gilphilbert_dongle/bootloader.bin differ diff --git a/OTA/Bridge/Gilphilbert_dongle/firmware.bin b/OTA/Bridge/Gilphilbert_dongle/firmware.bin new file mode 100644 index 00000000..8ef9b0b6 Binary files /dev/null and b/OTA/Bridge/Gilphilbert_dongle/firmware.bin differ diff --git a/OTA/Bridge/Gilphilbert_dongle/partitions.bin b/OTA/Bridge/Gilphilbert_dongle/partitions.bin new file mode 100644 index 00000000..2108af95 Binary files /dev/null and b/OTA/Bridge/Gilphilbert_dongle/partitions.bin differ diff --git a/OTA/Bridge/dev_kit/boot_app0.bin b/OTA/Bridge/dev_kit/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/Bridge/dev_kit/boot_app0.bin differ diff --git a/OTA/Bridge/dev_kit/bootloader.bin b/OTA/Bridge/dev_kit/bootloader.bin new file mode 100644 index 00000000..204061ac Binary files /dev/null and b/OTA/Bridge/dev_kit/bootloader.bin differ diff --git a/OTA/Bridge/dev_kit/firmware.bin b/OTA/Bridge/dev_kit/firmware.bin new file mode 100644 index 00000000..53af80a1 Binary files /dev/null and b/OTA/Bridge/dev_kit/firmware.bin differ diff --git a/OTA/Bridge/dev_kit/partitions.bin b/OTA/Bridge/dev_kit/partitions.bin new file mode 100644 index 00000000..951265fe Binary files /dev/null and b/OTA/Bridge/dev_kit/partitions.bin differ diff --git a/OTA/Build_bridge.bat b/OTA/Build_bridge.bat new file mode 100644 index 00000000..550bf0f3 --- /dev/null +++ b/OTA/Build_bridge.bat @@ -0,0 +1,15 @@ +@echo off +REM Save the current directory +set CUR_DIR=%cd% + +REM Change to the directory where the PlatformIO project is located (relative to this batch file) +cd /d "%~dp0\..\ESP32_master\" + +REM Run the PlatformIO build command +platformio run + +REM Change back to the original directory +cd /d %CUR_DIR% + +REM Pause to keep the command prompt open after the build +pause \ No newline at end of file diff --git a/OTA/Build_control_board.bat b/OTA/Build_control_board.bat new file mode 100644 index 00000000..130d838b --- /dev/null +++ b/OTA/Build_control_board.bat @@ -0,0 +1,15 @@ +@echo off +REM Save the current directory +set CUR_DIR=%cd% + +REM Change to the directory where the PlatformIO project is located (relative to this batch file) +cd /d "%~dp0\..\ESP32\" + +REM Run the PlatformIO build command +platformio run + +REM Change back to the original directory +cd /d %CUR_DIR% + +REM Pause to keep the command prompt open after the build +pause \ No newline at end of file diff --git a/OTA/ControlBoard/Gilphilbert_1_2/boot_app0.bin b/OTA/ControlBoard/Gilphilbert_1_2/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_1_2/boot_app0.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_1_2/bootloader.bin b/OTA/ControlBoard/Gilphilbert_1_2/bootloader.bin new file mode 100644 index 00000000..204061ac Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_1_2/bootloader.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_1_2/firmware.bin b/OTA/ControlBoard/Gilphilbert_1_2/firmware.bin new file mode 100644 index 00000000..c1c48a48 Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_1_2/firmware.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_1_2/partitions.bin b/OTA/ControlBoard/Gilphilbert_1_2/partitions.bin new file mode 100644 index 00000000..951265fe Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_1_2/partitions.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_2_0/boot_app0.bin b/OTA/ControlBoard/Gilphilbert_2_0/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_2_0/boot_app0.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_2_0/bootloader.bin b/OTA/ControlBoard/Gilphilbert_2_0/bootloader.bin new file mode 100644 index 00000000..f0633e8d Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_2_0/bootloader.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_2_0/firmware.bin b/OTA/ControlBoard/Gilphilbert_2_0/firmware.bin new file mode 100644 index 00000000..839ee76a Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_2_0/firmware.bin differ diff --git a/OTA/ControlBoard/Gilphilbert_2_0/partitions.bin b/OTA/ControlBoard/Gilphilbert_2_0/partitions.bin new file mode 100644 index 00000000..2108af95 Binary files /dev/null and b/OTA/ControlBoard/Gilphilbert_2_0/partitions.bin differ diff --git a/OTA/ControlBoard/Speedcrafter/boot_app0.bin b/OTA/ControlBoard/Speedcrafter/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/ControlBoard/Speedcrafter/boot_app0.bin differ diff --git a/OTA/ControlBoard/Speedcrafter/bootloader.bin b/OTA/ControlBoard/Speedcrafter/bootloader.bin new file mode 100644 index 00000000..d5923593 Binary files /dev/null and b/OTA/ControlBoard/Speedcrafter/bootloader.bin differ diff --git a/OTA/ControlBoard/Speedcrafter/firmware.bin b/OTA/ControlBoard/Speedcrafter/firmware.bin new file mode 100644 index 00000000..56bec599 Binary files /dev/null and b/OTA/ControlBoard/Speedcrafter/firmware.bin differ diff --git a/OTA/ControlBoard/Speedcrafter/partitions.bin b/OTA/ControlBoard/Speedcrafter/partitions.bin new file mode 100644 index 00000000..2108af95 Binary files /dev/null and b/OTA/ControlBoard/Speedcrafter/partitions.bin differ diff --git a/OTA/ControlBoard/esp32/boot_app0.bin b/OTA/ControlBoard/esp32/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/ControlBoard/esp32/boot_app0.bin differ diff --git a/OTA/ControlBoard/esp32/bootloader.bin b/OTA/ControlBoard/esp32/bootloader.bin new file mode 100644 index 00000000..d5923593 Binary files /dev/null and b/OTA/ControlBoard/esp32/bootloader.bin differ diff --git a/OTA/ControlBoard/esp32/firmware.bin b/OTA/ControlBoard/esp32/firmware.bin new file mode 100644 index 00000000..28bd836e Binary files /dev/null and b/OTA/ControlBoard/esp32/firmware.bin differ diff --git a/OTA/ControlBoard/esp32/partitions.bin b/OTA/ControlBoard/esp32/partitions.bin new file mode 100644 index 00000000..2108af95 Binary files /dev/null and b/OTA/ControlBoard/esp32/partitions.bin differ diff --git a/OTA/ControlBoard/esp32S3/boot_app0.bin b/OTA/ControlBoard/esp32S3/boot_app0.bin new file mode 100644 index 00000000..13562cab Binary files /dev/null and b/OTA/ControlBoard/esp32S3/boot_app0.bin differ diff --git a/OTA/ControlBoard/esp32S3/bootloader.bin b/OTA/ControlBoard/esp32S3/bootloader.bin new file mode 100644 index 00000000..204061ac Binary files /dev/null and b/OTA/ControlBoard/esp32S3/bootloader.bin differ diff --git a/OTA/ControlBoard/esp32S3/firmware.bin b/OTA/ControlBoard/esp32S3/firmware.bin new file mode 100644 index 00000000..95f69ffd Binary files /dev/null and b/OTA/ControlBoard/esp32S3/firmware.bin differ diff --git a/OTA/ControlBoard/esp32S3/partitions.bin b/OTA/ControlBoard/esp32S3/partitions.bin new file mode 100644 index 00000000..951265fe Binary files /dev/null and b/OTA/ControlBoard/esp32S3/partitions.bin differ diff --git a/OTA/Plugin/DiyActivePedal.dll b/OTA/Plugin/DiyActivePedal.dll new file mode 100644 index 00000000..bf413a87 Binary files /dev/null and b/OTA/Plugin/DiyActivePedal.dll differ diff --git a/OTA/README.md b/OTA/README.md new file mode 100644 index 00000000..49fd8529 --- /dev/null +++ b/OTA/README.md @@ -0,0 +1,5 @@ +Please use pio-run command in platformio CLI to build all the envs.
+Build-bridge.bat to build all envs in ESP32_MASTER folder
+Build-control-board to build all envs in ESP32 folder
+run copy_to_folder_bridge.bat to copy all bridge firmware to the folder after building.
+run copy_to_OTA_folder_ControlBoard to copy all control board firmware to the folder after building.
\ No newline at end of file diff --git a/OTA/copy_to_OTA_folder_ControlBoard.bat b/OTA/copy_to_OTA_folder_ControlBoard.bat new file mode 100644 index 00000000..291426b0 --- /dev/null +++ b/OTA/copy_to_OTA_folder_ControlBoard.bat @@ -0,0 +1,93 @@ +@echo off +set source=..\ESP32\.pio\build\esp32\firmware.bin +set destination=..\OTA\ControlBoard\esp32\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32\bootloader.bin +set destination=..\OTA\ControlBoard\esp32\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32\partitions.bin +set destination=..\OTA\ControlBoard\esp32\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg\firmware.bin +set destination=..\OTA\ControlBoard\esp32S3\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg\bootloader.bin +set destination=..\OTA\ControlBoard\esp32S3\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg\partitions.bin +set destination=..\OTA\ControlBoard\esp32S3\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg-gilphilbert\firmware.bin +set destination=..\OTA\ControlBoard\Gilphilbert_1_2\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg-gilphilbert\bootloader.bin +set destination=..\OTA\ControlBoard\Gilphilbert_1_2\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg-gilphilbert\partitions.bin +set destination=..\OTA\ControlBoard\Gilphilbert_1_2\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg-gilphilbert_2_0\firmware.bin +set destination=..\OTA\ControlBoard\Gilphilbert_2_0\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg-gilphilbert_2_0\bootloader.bin +set destination=..\OTA\ControlBoard\Gilphilbert_2_0\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32s3usbotg-gilphilbert_2_0\partitions.bin +set destination=..\OTA\ControlBoard\Gilphilbert_2_0\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32-speedcrafter\firmware.bin +set destination=..\OTA\ControlBoard\Speedcrafter\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32-speedcrafter\bootloader.bin +set destination=..\OTA\ControlBoard\Speedcrafter\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32\.pio\build\esp32-speedcrafter\partitions.bin +set destination=..\OTA\ControlBoard\Speedcrafter\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +echo File copied successfully. +pause diff --git a/OTA/copy_to_folder_bridge.bat b/OTA/copy_to_folder_bridge.bat new file mode 100644 index 00000000..a9a7f284 --- /dev/null +++ b/OTA/copy_to_folder_bridge.bat @@ -0,0 +1,57 @@ +@echo off +set source=..\ESP32_master\.pio\build\esp32s3-Fanatec\firmware.bin +set destination=..\OTA\Bridge\Fanatec_Bridge\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3-Fanatec\bootloader.bin +set destination=..\OTA\Bridge\Fanatec_Bridge\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3-Fanatec\partitions.bin +set destination=..\OTA\Bridge\Fanatec_Bridge\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3-gilphilbert\firmware.bin +set destination=..\OTA\Bridge\Gilphilbert_dongle\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3-gilphilbert\partitions.bin +set destination=..\OTA\Bridge\Gilphilbert_dongle\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3-gilphilbert\bootloader.bin +set destination=..\OTA\Bridge\Gilphilbert_dongle\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3usbotg\firmware.bin +set destination=..\OTA\Bridge\dev_kit\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3usbotg\bootloader.bin +set destination=..\OTA\Bridge\dev_kit\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +set source=..\ESP32_master\.pio\build\esp32s3usbotg\partitions.bin +set destination=..\OTA\Bridge\dev_kit\ + +echo Copying %source% to %destination%... +xcopy "%source%" "%destination%" /y + +echo File copied successfully. +pause \ No newline at end of file diff --git a/README.md b/README.md index cb2bf5c5..f522dba5 100644 --- a/README.md +++ b/README.md @@ -1,206 +1,72 @@ [![Arduino Build](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/actions/workflows/arduino.yml/badge.svg?branch=main)](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/actions/workflows/arduino.yml) [![Doxygen Action](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/actions/workflows/main.yml/badge.svg)](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/actions/workflows/main.yml) - - - -# DIY-Sim-Racing-FFB-Pedal - -# Disclaimer -This repository documents my research progress. I wanted to understand the necessary signal processing and control theory algorithms behind such a device. - -The FFB pedal is a robot and can be dangerous. Please watch [The Terminator](https://en.wikipedia.org/wiki/The_Terminator) before continuing. If not interacted with care, it may cause harm. I'm not responsible for any harm caused by this design suggestion. Use responsibly and at your own risk. - -# License -Shield: [![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] - -This work is licensed under a -[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa]. - +[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] +# License selection +This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa] [![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa] -The reason for that license selection is that at some point in time, individuals start -- to steal the sources and binaries and sell them on the internet -- mass production of FFB pedals in their living rooms to make money by taking parts from this project and Simucubes design files. - +The reason for that license selection is that at some point in time, individuals have done the following without contributing anything to this project. +- Taken the sources and binaries and sold them on the internet +- Started mass production of FFB Pedals from these designs in their living rooms to make money, by taking parts from this project and Simucube's design files +- The DIY FFB Pedal project is not affiliated with the video (https://www.youtube.com/watch?v=9ibAyHcSjO0) or its channel (https://www.youtube.com/@xiaoximu). We do not provide support or after-sales service for the content of this video or the associated website.
+ All that, without contributing anything to this project. [cc-by-nc-sa]: http://creativecommons.org/licenses/by-nc-sa/4.0/ [cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png [cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg +# DIY Sim Racing FFB Pedal +If you're used to standard spring or damper-based pedals with rumble motors attached, a force-feedback pedal is the next step. It uses a high power servo attached to a linear rail to control the motion of the pedal. This allows you to change how the pedal feels with a few changes on your PC, whether that's braking pressure, response or travel or the thottle weight or stiffness. You can even use profiles to build different "feels" for different cars, switching profiles between cars to give each vehicle a different driving experience. Additionally, since the pedal movement is controlled, the feedback it can produce is totally different - imaging feeling ABS feedback moving the pedal, the kick of the gear change through the throttle or feedback from road bumps through the pedals. It's an experience like no other! If that sounds like something you want to build for yourself, then read on! This project documents people who want to design and/or build their own force-feedback pedal. -# Related repos -For the sake of clarity, this project is divided into multiple repositorys: + + +> [!TIP] +> **Disclaimer** This repository documents my research progress. I wanted to understand the necessary signal processing and control theory algorithms behind such a device. + +> [!WARNING] +> The FFB pedal is a robot and can be dangerous. Please watch [The Terminator](https://en.wikipedia.org/wiki/The_Terminator) before continuing. If not interacted with care, it may cause harm. I'm not responsible for any harm caused by this design suggestion. Use responsibly and at your own risk. + +# Project repositories +This project has been divided into multiple repositories, each with differt purposes. The mechanical design repository provides the information you need to build the mechanics of ChrGri's pedal. It's not the only design, but it's strong and reliable. There are more options on the Wiki, and you can find even more designs on the Discord server. The Software repo (this repo) discusses how to select, order and connect the electronics, flash the firmware and get the pedal up and running. The final repo, contains designs for the recommended circuit boards that control the pedal. | Description | Link | :------------------------- | :------------------------- | -| Mechanical and electrical design | https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design | +| ChrGri's mechanical and electrical design | https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design | | Software (firmware, SimHub plugin, ...) |https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal | +| Control Board and Power Board design | https://github.com/gilphilbert/DIY-Sim-Racing-FFB-Pedal-PCBs | # Features -## Control of pedal parameters -To tune the pedal parameters, a SimHub plugin was developed, which communicates with the pedal over USB. - -## Effects -Currently ABS, TC and RPM vibration are supported effects. The SimHub plugin communicates with the pedal and triggers game effects as parameterized.The effects and its description can be found in [wiki](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/wiki/Pedal-Effects). - -## Servo tuning -The used microcontroller has software to communicate with the used iSV57 servo. Therefore, it can tune the servos PID loop and read certain servo states like position, torque, power. - -## Joystick data stream -The joystick/gamepad data is provided via three redundant channels -1) Bluetooth -2) 0V-3.3V output analog signal. Can be read by e.g. https://gp2040-ce.info/. The pin 25 was used for analog output. -3) vJoy gamecontroller (only available when SimHub runs, also need enable control map plugin). - -To provide native USB HID output, development with ESP32 S3 started, it's working, but not stable yet, [see](https://github.com/espressif/arduino-esp32/issues/9582#issuecomment-2219722111). - -## Pedals in action +- SimHub integration +- Integration into a number of different simulators +- Tune pedal parameters +- Connect over USB or wireless +- Supports Analog output for integration into additional devices +- Multiple feedback types (more details in the [Wiki](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/wiki/Pedal-Effects)) + - ABS (AntiLock Braking System) + - Traction Control + - RPM vibration + - Road rumble +- Powerful servo that can generate torque for heavy braking exceeding 100KGs when paired with a suitable linear rail + +# See the pedals in action [![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/i2e1ukc1ylA/0.jpg)](https://www.youtube.com/watch?v=i2e1ukc1ylA) -More pedal action examples can be found in the Discord. - +More pedal action examples can be found on the [Wiki](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/wiki/Hardware-designs) and the [Discord server](https://discord.gg/zTfQaxpAUz) # Contributions A lot of awesome devs have helped this project grow. Just to name a few: +- [tjfenwick](https://github.com/tjfenwick) started the project with an initial implementation +- [tcfshcrw](https://github.com/tcfshcrw) helped to elevate the SimHub plugin to its current form, added a ton of new pedal effects, provides support on Discord, is a great guy and much more! +- [MichaelJFr](https://github.com/MichaelJFr) helped by refactoring the code at the beginning of this project. Fruitful discussions let to the implementation of the control-loop strategies +- [Ibakha](https://github.com/Ibakha) Our Discord channel CEO +- [gilphilbert](https://github.com/gilphilbert) developed custom PCB assemblies, refactored the Wiki and created the Web Flash tool -- [tjfenwick](https://github.com/tjfenwick) started the project with an initial implementation. -- [tcfshcrw](https://github.com/tcfshcrw) helped to elevate the Simhub plugin to its current form, added a ton of pedal effects, hardware and discord support, good guy and much more. -- [MichaelJFr](https://github.com/MichaelJFr) helped with refactoring the code at the beginning of this project. Fruitful discussions let to the implementation of the control-loop strategies. -- [Ibakha](https://github.com/Ibakha) Discord channel CEO. - - -# Wiki -Detailed descriptions of certain aspects can be found on the dedicated [Wiki page](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/wiki): - - -# Discord -A [Discord](https://discord.gg/j8QhD5hCv7) server has been created to allow joint research. - - -# Hardware -During the development of this project, PCBs to hold the electric components were developed, see below
- . - -Also a (mostly) 3d printable mechanical design was designed and optimized to withstand the high forces of this application, see below
- . - - -Please refer to the https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/tree/main?tab=readme-ov-file#related-repos section to access the design files. - -
-
-
+# How to get started +## Read the Wiki +Detailed descriptions of all aspects of the build can be found on the dedicated [Wiki page](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/wiki), which includes instructions on how to select parts, build the pedals and integrate them into your games -Examples other awesome DIYers have done are listed below: +## Join the Discord server +Our [Discord server](https://discord.gg/zTfQaxpAUz) has thousands of users just like you and contains additional designs, insight and provides a place to find answers to all of your questions. -| Design | Link | -:------------------------- | :------------------------- -| | [Tjfenwick's design](https://github.com/tjfenwick/DIY-Sim-Racing-Active-Pedal)| -| | [Bjoes design](https://github.com/Bjoes/DIY-Active-pedal-mechanical-design)| -| | [GWiz's design](https://www.printables.com/de/model/557527-simucube-style-active-pedal/files)| -| | [shf90's design](https://www.thingiverse.com/thing:6414587)| - - -# Software - -## ESP32 code - -### Architecture +# Architecture A Doxygen report of the sources can be found [here](https://chrgri.github.io/DIY-Sim-Racing-FFB-Pedal/Arduino/html/index.html). -### Install ESP32 driver -The drivers can be found here [here](https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers). - -### Firmware generation and flashing -Firmware can be built and flashed via VS Code. Prebuilt binaries can be flashed e.g. via ESP32 webflasher of the [flashing tool]([https://www.espressif.com/sites/default/files/tools/flash_download_tool_3.9.3.zip](https://www.espressif.com/en/support/download/other-tools)). - -#### Built from source (via VS Code) -See this [guide](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/wiki/VScode-IDE-setup). - -#### Flash prebuilt binaries via web flasher -The binaries are available [here](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/releases). They can be flashed via the ESP [webflasher](https://esp.huhn.me/). Another [Webflasher](https://nabucasa.github.io/esp-web-flasher/). -##### ESP32 -Memory address | File -:-------------------------:|:-------------------------: -| 0x1000 | bootloader.bin | -| 0x8000 | partitions.bin | -| 0xe000 | boot_app0.bin | -| 0x10000 | firmware.bin | - -##### ESP32S3 -Memory address | File -:-------------------------:|:-------------------------: -| 0x0000 | bootloader.bin | -| 0x8000 | partitions.bin | -| 0xe000 | boot_app0.bin | -| 0x10000 | firmware.bin | - -## iSV57T-130 servo config tuning -The iSV57T allows parameter tuning via its RS232 interface. To tune the servo towards this application, I executed the following [steps](StepperParameterization/StepperTuning.md). - -With the current [PCB](Wiring/Esp32_V3) design, the ESP can directly communicate with the iSV57T servo. Manual tuning as described before isn't necessary anymore. A description of the steps I undertook to decode the communication protocol can be found on the Disord server. Additional features such as sensorless homing and lost-step recovery were developed and integrated with the help of this communication. - -## SimHub plugin: -The SimHub plugin was designed to communicate with the ESP to (a) modify the pedal configuration, e.g. the force vs. travel parameterization and (b) to trigger effects such as ABS oscillations. - -![image](SimHubPlugin/Images/Plugin-UI.png) - -To install the plugin, the plugin [DiyActivePedal.dll](https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal/releases) has to be copied to the SimHub directory, e.g. C:/Program Files (x86)/SimHub - -# Steps after flashing the firmware -The pedal will not move initially after flashing. One has to open the SimHub plugin, connect to the pedal, and send a config with non-zero PID values. -Recommended PID values are: - -``` -P=0.2-0.4 -I=50-150 -D=0 -``` - -After sending the initial config, power cycling of the pedal is necessary. The pedal should move afterward. - - -# Error handling -## Pedal doesn't move after initial setup -1. Make sure, that you follow the above instructions. The default PID values are set to 0 thus the pedal will not move. You have to send non-zero PID values and restart the pedal to observe pedal travel. -2. Open the serial monitor in Arduino IDE, set the baud rate to 921600, and restart the pedal. You should see some debug info. Make a screenshot and kindly ask the Discord server for help. - -## Bluetooth doesn't show gamepad data -Install DirectX 9 - -## The serial monitor shows a message "Couldn't load config from EPROM due to version mismatch" -Install a SimHub plugin matching the ESP firmware you installed and send a config to the pedal. - -## The com port showed access denied or can not connect -Check the arduino plugin scan setting, please use scan only specfiec port as below.
- - - - -# Todo - -ESP code: -- [ ] Add automatic system identification of pedal response -- [ ] Add model-predictive-control to the ESP code for the improved pedal response -- [x] Add field to invert motor and losdcell direction -- [x] send joystick data to simhub plugin and provide data as vJoy gamecontroller -- [x] allow effects to move stepper beyond configured max/min position, but not the measured homing positions -- [x] Optimize iSV57 communication - - [ ] Let the communication task run from the beginning of the setup routine - - [x] Read pedal state every cycle (currently, the pedal performance is degraded) - - -SimHub plugin: -- [ ] Send SimHub data via wifi to ESP -- [x] GUI design improvements for the SimHub plugin -- [x] JSON deserialization make compatible with older revisions -- [ ] include the types header file and use it -- [ ] Make use of effects from the ShakeIt plugin -- [ ] add OTA update for esp firmware -- [x] automatic serial monitor update -- [ ] serial plotter -- [x] add different abs effect patterns, e.g. sawtooth -- [x] make effects proportional to force or travel selectable by dropdown menu - -Misc: -- [ ] Create a video describing the build progress and the features -- [ ] Add Doxygen + Graphviz to the project to automatically generate documentation, architectural design overview, etc. diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo.csproj.dtbcache.json b/SimHubPlugin/.vs/User.PluginSdkDemo.csproj.dtbcache.json index 025dcf1d..28fcc628 100644 --- a/SimHubPlugin/.vs/User.PluginSdkDemo.csproj.dtbcache.json +++ b/SimHubPlugin/.vs/User.PluginSdkDemo.csproj.dtbcache.json @@ -1 +1 @@ -{"RootPath":"C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin","ProjectFileName":"User.PluginSdkDemo.csproj","Configuration":"Release|AnyCPU","FrameworkPath":"","Sources":[{"SourceFile":"CubicSpline.cs"},{"SourceFile":"DataPluginDemo.cs"},{"SourceFile":"DataPluginDemoSettings.cs"},{"SourceFile":"Properties\\AssemblyInfo.cs"},{"SourceFile":"Properties\\Resources.Designer.cs"},{"SourceFile":"SettingsControlDemo.xaml.cs"},{"SourceFile":"obj\\Release\\.NETFramework,Version=v4.8.AssemblyAttributes.cs"},{"SourceFile":"C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\obj\\Release\\SettingsControlDemo.g.cs"}],"References":[{"Reference":"C:\\Program Files (x86)\\SimHub\\AvalonDock.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\AvalonDock.Themes.VS2013.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\GameReaderCommon.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\InputManagerCS.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\log4net.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\MahApps.Metro.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\packages\\Microsoft.Bcl.AsyncInterfaces.8.0.0\\lib\\net462\\Microsoft.Bcl.AsyncInterfaces.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\Microsoft.CSharp.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\mscorlib.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\Newtonsoft.Json.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\PresentationCore.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\PresentationFramework.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\SimHub.Logging.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\SimHub.Plugins.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Buffers.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Core.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Data.DataSetExtensions.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Data.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Drawing.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Memory.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Net.Http.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Numerics.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Numerics.Vectors.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Runtime.CompilerServices.Unsafe.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Runtime.Serialization.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.ServiceModel.Web.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\packages\\System.Text.Encodings.Web.8.0.0\\lib\\net462\\System.Text.Encodings.Web.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Text.Json.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Threading.Tasks.Extensions.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.ValueTuple.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Windows.Forms.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xaml.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.Linq.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\vJoyInterfaceWrap.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\WindowsBase.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\WoteverCommon.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""}],"Analyzers":[],"Outputs":[{"OutputItemFullPath":"C:\\Program Files (x86)\\SimHub\\DiyActivePedal.dll","OutputItemRelativePath":"DiyActivePedal.dll"},{"OutputItemFullPath":"C:\\Program Files (x86)\\SimHub\\DiyActivePedal.pdb","OutputItemRelativePath":"DiyActivePedal.pdb"}],"CopyToOutputEntries":[]} \ No newline at end of file +{"RootPath":"Y:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin","ProjectFileName":"User.PluginSdkDemo.csproj","Configuration":"Debug|AnyCPU","FrameworkPath":"","Sources":[{"SourceFile":"CubicSpline.cs"},{"SourceFile":"DataPluginDemo.cs"},{"SourceFile":"DataPluginDemoSettings.cs"},{"SourceFile":"Properties\\AssemblyInfo.cs"},{"SourceFile":"Properties\\Resources.Designer.cs"},{"SourceFile":"SettingsControlDemo.xaml.cs"},{"SourceFile":"obj\\Debug\\.NETFramework,Version=v4.8.AssemblyAttributes.cs"},{"SourceFile":"Y:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\obj\\Debug\\SettingsControlDemo.g.cs"}],"References":[{"Reference":"C:\\Program Files (x86)\\SimHub\\AvalonDock.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\AvalonDock.Themes.VS2013.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\GameReaderCommon.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\InputManagerCS.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\log4net.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\MahApps.Metro.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\Microsoft.Bcl.AsyncInterfaces.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\Microsoft.CSharp.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\mscorlib.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\Newtonsoft.Json.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\PresentationCore.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\PresentationFramework.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\SimHub.Logging.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\SimHub.Plugins.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Buffers.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Core.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.DataSetExtensions.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Drawing.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Memory.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Net.Http.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Numerics.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Numerics.Vectors.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Runtime.CompilerServices.Unsafe.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Runtime.Serialization.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.ServiceModel.Web.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"Y:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\packages\\System.Text.Encodings.Web.8.0.0\\lib\\net462\\System.Text.Encodings.Web.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Text.Json.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.Threading.Tasks.Extensions.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\System.ValueTuple.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Windows.Forms.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xaml.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.Linq.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\vJoyInterfaceWrap.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\WINDOWS\\System32\\WinMetadata\\Windows.Data.winmd","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\WINDOWS\\System32\\WinMetadata\\Windows.UI.winmd","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\WindowsBase.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\SimHub\\WoteverCommon.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""}],"Analyzers":[],"Outputs":[{"OutputItemFullPath":"Y:\\Program Files (x86)\\SimHub\\DiyActivePedal.dll","OutputItemRelativePath":"DiyActivePedal.dll"},{"OutputItemFullPath":"Y:\\Program Files (x86)\\SimHub\\DiyActivePedal.pdb","OutputItemRelativePath":"DiyActivePedal.pdb"}],"CopyToOutputEntries":[]} \ No newline at end of file diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/1778ca7b-1680-4dc2-aa14-5d6628398026.vsidx b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/1778ca7b-1680-4dc2-aa14-5d6628398026.vsidx new file mode 100644 index 00000000..6f5dbf8f Binary files /dev/null and b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/1778ca7b-1680-4dc2-aa14-5d6628398026.vsidx differ diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/1829902c-01ac-45b3-a8d9-46b96d95a1f0.vsidx b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/1829902c-01ac-45b3-a8d9-46b96d95a1f0.vsidx new file mode 100644 index 00000000..b40d1c27 Binary files /dev/null and b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/1829902c-01ac-45b3-a8d9-46b96d95a1f0.vsidx differ diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/a1fd4c7c-e114-4a13-8c1f-80024347cf5b.vsidx b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/a1fd4c7c-e114-4a13-8c1f-80024347cf5b.vsidx deleted file mode 100644 index d8128afc..00000000 Binary files a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/a1fd4c7c-e114-4a13-8c1f-80024347cf5b.vsidx and /dev/null differ diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/a9fa2edd-2004-4cab-8d38-b032a899ce84.vsidx b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/a9fa2edd-2004-4cab-8d38-b032a899ce84.vsidx new file mode 100644 index 00000000..6f5dbf8f Binary files /dev/null and b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/a9fa2edd-2004-4cab-8d38-b032a899ce84.vsidx differ diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/fe76e03b-b302-466f-a8da-0ea9a719a043.vsidx b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/fe76e03b-b302-466f-a8da-0ea9a719a043.vsidx new file mode 100644 index 00000000..6f5dbf8f Binary files /dev/null and b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/fe76e03b-b302-466f-a8da-0ea9a719a043.vsidx differ diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/read.lock b/SimHubPlugin/.vs/User.PluginSdkDemo/FileContentIndex/read.lock new file mode 100644 index 00000000..e69de29b diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/v17/.suo b/SimHubPlugin/.vs/User.PluginSdkDemo/v17/.suo index 14432892..34a40800 100644 Binary files a/SimHubPlugin/.vs/User.PluginSdkDemo/v17/.suo and b/SimHubPlugin/.vs/User.PluginSdkDemo/v17/.suo differ diff --git a/SimHubPlugin/.vs/User.PluginSdkDemo/v17/DocumentLayout.json b/SimHubPlugin/.vs/User.PluginSdkDemo/v17/DocumentLayout.json index f2dac144..41c933d6 100644 --- a/SimHubPlugin/.vs/User.PluginSdkDemo/v17/DocumentLayout.json +++ b/SimHubPlugin/.vs/User.PluginSdkDemo/v17/DocumentLayout.json @@ -1,22 +1,22 @@ { "Version": 1, - "WorkspaceRootPath": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\", + "WorkspaceRootPath": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|c:\\users\\tcfshcrw\\documents\\github\\diy-sim-racing-ffb-pedal\\simhubplugin\\settingscontroldemo.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}", - "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:settingscontroldemo.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}" + "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\dataplugindemo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:dataplugindemo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\settingscontroldemo.xaml.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:settingscontroldemo.xaml.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\dataplugindemosettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:dataplugindemosettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\dataplugindemosettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:dataplugindemosettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\settingscontroldemo.xaml.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:settingscontroldemo.xaml.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\dataplugindemo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:dataplugindemo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|x:\\ac mod\\private works\\activepedal\\simhub_plugin\\v86-1106\\simhubplugin\\settingscontroldemo.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}", + "RelativeMoniker": "D:0:0:{833040C9-FE5E-4CCF-B21D-71979E049B6B}|User.PluginSdkDemo.csproj|solutionrelative:settingscontroldemo.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}" }, { "AbsoluteMoniker": "D:0:0:{00000000-0000-0000-0000-000000000000}|\u003CSolution\u003E|User.PluginSdkDemo||{04B8AB82-A572-4FEF-95CE-5222444B6B64}|" @@ -29,53 +29,54 @@ "DocumentGroups": [ { "DockedWidth": 1796, - "SelectedChildIndex": 3, + "SelectedChildIndex": 0, "Children": [ { "$type": "Document", - "DocumentIndex": 3, + "DocumentIndex": 0, "Title": "DataPluginDemo.cs", - "DocumentMoniker": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\DataPluginDemo.cs", + "DocumentMoniker": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\DataPluginDemo.cs", "RelativeDocumentMoniker": "DataPluginDemo.cs", - "ToolTip": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\DataPluginDemo.cs", + "ToolTip": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\DataPluginDemo.cs", "RelativeToolTip": "DataPluginDemo.cs", - "ViewState": "AQIAANAAAAAAAAAAAAAcwN8DAAA3AAAA", + "ViewState": "AQIAANoBAAAAAAAAAAAIwNwAAAAAAAAA", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2024-09-22T01:27:42.551Z" + "WhenOpened": "2024-09-22T01:27:42.551Z", + "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 1, + "DocumentIndex": 2, "Title": "SettingsControlDemo.xaml.cs", - "DocumentMoniker": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\SettingsControlDemo.xaml.cs", + "DocumentMoniker": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\SettingsControlDemo.xaml.cs", "RelativeDocumentMoniker": "SettingsControlDemo.xaml.cs", - "ToolTip": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\SettingsControlDemo.xaml.cs", + "ToolTip": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\SettingsControlDemo.xaml.cs", "RelativeToolTip": "SettingsControlDemo.xaml.cs", - "ViewState": "AQIAADoKAAAAAAAAAAAawMwEAAA7AAAA", + "ViewState": "AQIAAIgIAAAAAAAAAAAuwJUIAABLAAAA", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2024-09-22T01:27:42.579Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 2, + "DocumentIndex": 1, "Title": "DataPluginDemoSettings.cs", - "DocumentMoniker": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\DataPluginDemoSettings.cs", + "DocumentMoniker": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\DataPluginDemoSettings.cs", "RelativeDocumentMoniker": "DataPluginDemoSettings.cs", - "ToolTip": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\DataPluginDemoSettings.cs", + "ToolTip": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\DataPluginDemoSettings.cs", "RelativeToolTip": "DataPluginDemoSettings.cs", - "ViewState": "AQIAAB0AAAAAAAAAAAAAwCgAAAA/AAAA", + "ViewState": "AQIAACYAAAAAAAAAAAAAwCgAAAA/AAAA", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2024-09-22T01:27:42.58Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 0, + "DocumentIndex": 3, "Title": "SettingsControlDemo.xaml", - "DocumentMoniker": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\SettingsControlDemo.xaml", + "DocumentMoniker": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\SettingsControlDemo.xaml", "RelativeDocumentMoniker": "SettingsControlDemo.xaml", - "ToolTip": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\SettingsControlDemo.xaml", + "ToolTip": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\SettingsControlDemo.xaml", "RelativeToolTip": "SettingsControlDemo.xaml", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003549|", "WhenOpened": "2024-09-22T01:27:42.788Z", @@ -85,24 +86,14 @@ "$type": "Document", "DocumentIndex": 4, "Title": "User.PluginSdkDemo", - "DocumentMoniker": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\User.PluginSdkDemo.csproj", + "DocumentMoniker": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\User.PluginSdkDemo.csproj", "RelativeDocumentMoniker": "User.PluginSdkDemo.csproj", - "ToolTip": "C:\\Users\\tcfshcrw\\Documents\\GitHub\\DIY-Sim-Racing-FFB-Pedal\\SimHubPlugin\\User.PluginSdkDemo.csproj", + "ToolTip": "X:\\AC MOD\\private works\\ActivePedal\\simhub_plugin\\V86-1106\\SimHubPlugin\\User.PluginSdkDemo.csproj", "RelativeToolTip": "User.PluginSdkDemo.csproj", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|", "WhenOpened": "2024-01-21T21:54:53.464Z" } ] - }, - { - "DockedWidth": 583, - "SelectedChildIndex": -1, - "Children": [ - { - "$type": "Bookmark", - "Name": "ST:0:0:{d78612c7-9962-4b83-95d9-268046dad23a}" - } - ] } ] } diff --git a/SimHubPlugin/DataPluginDemo.cs b/SimHubPlugin/DataPluginDemo.cs index 040bdabc..0cba0517 100644 --- a/SimHubPlugin/DataPluginDemo.cs +++ b/SimHubPlugin/DataPluginDemo.cs @@ -1,6 +1,10 @@ using GameReaderCommon; +using log4net.Plugin; +using NCalc; + //using log4net.Plugin; using SimHub.Plugins; +using SimHub.Plugins.DataPlugins.DataCore; using SimHub.Plugins.DataPlugins.RGBMatrixDriver.Settings; using SimHub.Plugins.DataPlugins.ShakeItV3.UI.Effects; using SimHub.Plugins.OutputPlugins.Dash.GLCDTemplating; @@ -14,6 +18,7 @@ using System.Windows.Media; using Windows.UI.Notifications; using static System.Net.Mime.MediaTypeNames; +using IPlugin = SimHub.Plugins.IPlugin; @@ -25,15 +30,16 @@ static class Constants { // payload revisiom - public const uint pedalConfigPayload_version = 141; + public const uint pedalConfigPayload_version = 142; // pyload types public const uint pedalConfigPayload_type = 100; public const uint pedalActionPayload_type = 110; public const uint pedalStateBasicPayload_type = 120; - public const uint pedalStateExtendedPayload_type = 130; + public const uint pedalStateExtendedPayload_type = 130; public const uint bridgeStatePayloadType = 210; + public const uint Basic_Wifi_info_type = 220; } @@ -219,8 +225,8 @@ public struct payloadPedalConfig // OTA update flag //public byte OTA_flag; - // OTA update flag - public byte enableReboot_u8; + // Misc flags + public byte stepLossFunctionFlags_u8; } @@ -268,6 +274,19 @@ public struct DAP_bridge_state_st public payloadFooter payloadFooter_; }; +[StructLayout(LayoutKind.Sequential, Pack = 1)] +unsafe public struct Basic_WIfi_info +{ + public byte payload_Type; + public byte device_ID; + public byte wifi_action; + public byte mode_select; + public byte SSID_Length; + public byte PASS_Length; + public fixed byte WIFI_SSID[30]; + public fixed byte WIFI_PASS[30]; +}; + namespace User.PluginSdkDemo { [PluginDescription("The Plugin was for FFB pedal, To tune the pedal parameters and communicates with the pedal over USB.")] @@ -315,8 +334,13 @@ public class DIY_FFB_Pedal : IPlugin, IDataPlugin, IWPFSettingsV2 public byte PedalErrorCode = 0; public byte PedalErrorIndex = 0; public byte[] random_pedal_action_interval=new byte[3] { 50,51,53}; - - + public byte Rudder_RPM_Effect_last_value = 0; + public byte Rudder_G_last_value = 0; + public bool MSFS_status = false; + public byte Rudder_Wind_Force_last_value = 0; + public bool MSFS_Plugin_Status = false; + public string Simhub_version = ""; + public bool Version_Check_Simhub_MSFS = false; //effect trigger timer DateTime[] Action_currentTime = new DateTime[3]; @@ -334,17 +358,10 @@ public class DIY_FFB_Pedal : IPlugin, IDataPlugin, IWPFSettingsV2 //Road effect DateTime RoadTrigger_currentTime = DateTime.Now; DateTime RoadTrigger_lastTime = DateTime.Now; + //Rudder update + DateTime Rudder_Action_currentTime = DateTime.Now; + DateTime Rudder_Action_lastTime = DateTime.Now; - //// payload revisiom - //public uint pedalConfigPayload_version = 110; - - //// pyload types - //public uint pedalConfigPayload_type = 100; - //public uint pedalActionPayload_type = 110; - - //public SettingsControlDemo settings { get; } - - //SettingsControlDemo wpfHandler; //https://www.c-sharpcorner.com/uploadfile/eclipsed4utoo/communicating-with-serial-port-in-C-Sharp/ @@ -446,6 +463,47 @@ public byte[] getBytes_Bridge(DAP_bridge_state_st aux) return myBuffer; } + + public byte[] getBytes_Basic_Wifi_info(Basic_WIfi_info aux) + { + int length = Marshal.SizeOf(aux); + IntPtr ptr = Marshal.AllocHGlobal(length); + byte[] myBuffer = new byte[length]; + + Marshal.StructureToPtr(aux, ptr, true); + Marshal.Copy(ptr, myBuffer, 0, length); + Marshal.FreeHGlobal(ptr); + + return myBuffer; + } + public string Ncalc_reading(String expression) + { + string value = ""; + try + { + NCalc.Expression exp = new NCalc.Expression(expression); + exp.ResolveParameter += delegate (string name, ParameterResolveArgs rarg) + { + rarg.Result = () => PluginManager.GetPropertyValue(name); + }; + + if (exp.HasErrors() == false) + { + value = exp.Evaluate().ToString(); + } + else + { + value = "Error"; + } + + } + catch (Exception ex) + { + SimHub.Logging.Current.Error(ex.Message); + } + + return value; + } unsafe public void DataUpdate(PluginManager pluginManager, ref GameData data) { @@ -458,6 +516,13 @@ unsafe public void DataUpdate(PluginManager pluginManager, ref GameData data) byte Road_impact_value = 0; byte CV1_value = 0; byte CV2_value = 0; + double MSFS_RPM_Value_Simhub = 0; + double RUDDER_DEFLECTION_Simhub = 0; + double RELATIVE_WIND_VELOCITY_BODY_Z_Simhub = 0; + double ACCELERATION_BODY_Z_Simhub = 0; + double ACCELERATION_BODY_Y_Simhub = 0; + bool MSFS_running_simhub = false; + //bool WS_flag = false; if (data.GamePaused | (!data.GameRunning)) @@ -713,33 +778,49 @@ unsafe public void DataUpdate(PluginManager pluginManager, ref GameData data) } } } - //custom effcts - if (Settings.CV1_enable_flag[pedalIdx] == true) + //custom effcts + if (Settings.CV1_enable_flag[pedalIdx] == true) + { + //CV1_value = Convert.ToByte(pluginManager.GetPropertyValue(Settings.CV1_bindings[pedalIdx])); + string temp_string = Ncalc_reading(Settings.CV1_bindings[pedalIdx]); + if (temp_string != "Error") { - if (pluginManager.GetPropertyValue(Settings.CV1_bindings[pedalIdx]) != null) - { - - CV1_value = Convert.ToByte(pluginManager.GetPropertyValue(Settings.CV1_bindings[pedalIdx])); - if (CV1_value > (Settings.CV1_trigger[pedalIdx])) - { - tmp.payloadPedalAction_.Trigger_CV_1 = 1; - update_flag = true; - } - } + CV1_value = Convert.ToByte(temp_string); } - if (Settings.CV2_enable_flag[pedalIdx] == true) + else { - if (pluginManager.GetPropertyValue(Settings.CV2_bindings[pedalIdx]) != null) - { + CV1_value = 0; + SimHub.Logging.Current.Error("CV1 Reading error"); + } - CV2_value = Convert.ToByte(pluginManager.GetPropertyValue(Settings.CV2_bindings[pedalIdx])); - if (CV2_value > (Settings.CV2_trigger[pedalIdx])) - { - tmp.payloadPedalAction_.Trigger_CV_2 = 1; - update_flag = true; - } - } + + if (CV1_value > (Settings.CV1_trigger[pedalIdx])) + { + tmp.payloadPedalAction_.Trigger_CV_1 = 1; + update_flag = true; } + } + if (Settings.CV2_enable_flag[pedalIdx] == true) + { + + //CV2_value = Convert.ToByte(pluginManager.GetPropertyValue(Settings.CV2_bindings[pedalIdx])); + string temp_string = Ncalc_reading(Settings.CV2_bindings[pedalIdx]); + if (temp_string != "Error") + { + CV2_value = Convert.ToByte(temp_string); + } + else + { + CV2_value = 0; + SimHub.Logging.Current.Error("CV2 Reading error"); + } + if (CV2_value > (Settings.CV2_trigger[pedalIdx])) + { + tmp.payloadPedalAction_.Trigger_CV_2 = 1; + update_flag = true; + } + + } @@ -827,6 +908,25 @@ unsafe public void DataUpdate(PluginManager pluginManager, ref GameData data) } } + + if (((string)pluginManager.GetPropertyValue("DataCorePlugin.CurrentGame")) == "FlightSimulator2020" || ((string)pluginManager.GetPropertyValue("DataCorePlugin.CurrentGame")) == "FlightSimulator2024") + { + MSFS_RPM_Value_Simhub = Convert.ToDouble(pluginManager.GetPropertyValue("DataCorePlugin.GameRawData.FSStatus.GeneralEngPctMaxRPM1")); + //RUDDER_DEFLECTION_Simhub = Convert.ToDouble(pluginManager.GetPropertyValue("DataCorePlugin.GameRawData.FSStatus.RUDDER_DEFLECTION")); + RELATIVE_WIND_VELOCITY_BODY_Z_Simhub = Convert.ToDouble(pluginManager.GetPropertyValue("DataCorePlugin.GameRawData.FSStatus.AircraftWindZ")); + ACCELERATION_BODY_Z_Simhub = Convert.ToDouble(pluginManager.GetPropertyValue("DataCorePlugin.GameRawData.FSStatus.AccelerationBodyZ")); + ACCELERATION_BODY_Y_Simhub = Convert.ToDouble(pluginManager.GetPropertyValue("DataCorePlugin.GameRawData.FSStatus.AccelerationBodyY")); + MSFS_running_simhub = true; + } + else + { + MSFS_RPM_Value_Simhub = 0; + //RUDDER_DEFLECTION_Simhub = 0; + RELATIVE_WIND_VELOCITY_BODY_Z_Simhub = 0; + ACCELERATION_BODY_Z_Simhub = 0; + ACCELERATION_BODY_Y_Simhub = 0; + MSFS_running_simhub = false; + } } else @@ -935,24 +1035,168 @@ unsafe public void DataUpdate(PluginManager pluginManager, ref GameData data) System.Threading.Thread.Sleep(5); } } + + + Rudder_enable_flag = false; + System.Threading.Thread.Sleep(50); + } + SystemSounds.Beep.Play(); + + } + + //Rudder effect runtine + //check MSFS plugin version + if (((string)pluginManager.GetPropertyValue("FlightPlugin.MSFS_PLUGIN_VERSION")) == "1.0.0.0") + { + MSFS_Plugin_Status = true; + } + else + { + MSFS_Plugin_Status = false; + } + + if (Rudder_status) + { + if (MSFS_Plugin_Status || MSFS_running_simhub) + { + if (Convert.ToByte(pluginManager.GetPropertyValue("FlightPlugin.IS_MSFS_DATA_UPDATING")) == 1) + { + MSFS_status = true; + + } else { - if (_serialPort[PIDX].IsOpen) + if (MSFS_status) { - // clear inbuffer - _serialPort[PIDX].DiscardInBuffer(); - - // send query command - _serialPort[PIDX].Write(newBuffer, 0, newBuffer.Length); + clear_action = true; + MSFS_status = false; } - } + if (MSFS_status || MSFS_running_simhub) + { + Rudder_Action_currentTime = DateTime.Now; + TimeSpan diff_action = Rudder_Action_currentTime - Rudder_Action_lastTime; + int millisceonds_action = (int)diff_action.TotalMilliseconds; + if (millisceonds_action > 40) + { + bool Rudder_Effect_update_b = false; + DAP_action_st tmp; + tmp.payloadHeader_.version = (byte)Constants.pedalConfigPayload_version; + tmp.payloadHeader_.payloadType = (byte)Constants.pedalActionPayload_type; + tmp.payloadPedalAction_.triggerAbs_u8 = 0; + tmp.payloadPedalAction_.RPM_u8 = Rudder_RPM_Effect_last_value; + tmp.payloadPedalAction_.G_value = 128; + tmp.payloadPedalAction_.WS_u8 = 0; + tmp.payloadPedalAction_.impact_value = Rudder_G_last_value; + //tmp.payloadPedalAction_.impact_value = 0; + tmp.payloadPedalAction_.Trigger_CV_1 = 0; + tmp.payloadPedalAction_.Trigger_CV_2 = 0; + tmp.payloadPedalAction_.Rudder_action = 0; + tmp.payloadPedalAction_.Rudder_brake_action = 0; + //action here + + //RPM effect + if (Settings.Rudder_RPM_effect_b) + { + byte Rudder_RPM_value = 0; + if (MSFS_Plugin_Status) + { + Rudder_RPM_value = Convert.ToByte(pluginManager.GetPropertyValue("FlightPlugin.FlightData.GENERAL_ENG_PCT_MAX_RPM_1")); + } + if (MSFS_running_simhub) + { + Rudder_RPM_value = (byte)MSFS_RPM_Value_Simhub; + } + + + + if (Math.Abs(Rudder_RPM_value - Rudder_RPM_Effect_last_value) > 3) + { + tmp.payloadPedalAction_.RPM_u8 = Rudder_RPM_value; + Rudder_Effect_update_b = true; + Rudder_Action_lastTime = DateTime.Now; + Rudder_RPM_Effect_last_value = Rudder_RPM_value; + } + } - - Rudder_enable_flag = false; - System.Threading.Thread.Sleep(50); + if (Settings.Rudder_ACC_effect_b) + { + double Rudder_Wind_Froce_Ratio = 0; + + double RELATIVE_WIND_VELOCITY_BODY_Z = 0; + double Rudder_Radians = 0; + double Rudder_G_value_dz = 0; + double Rudder_G_value_dy = 0; + if (MSFS_Plugin_Status) + { + Rudder_G_value_dz = Convert.ToDouble(pluginManager.GetPropertyValue("FlightPlugin.FlightData.ACCELERATION_BODY_Z")); + Rudder_G_value_dy = Convert.ToDouble(pluginManager.GetPropertyValue("FlightPlugin.FlightData.ACCELERATION_BODY_Y")); + RELATIVE_WIND_VELOCITY_BODY_Z = Math.Abs(Convert.ToDouble(pluginManager.GetPropertyValue("FlightPlugin.FlightData.RELATIVE_WIND_VELOCITY_BODY_Z"))); + Rudder_Radians = Math.Abs(Convert.ToDouble(pluginManager.GetPropertyValue("FlightPlugin.FlightData.RUDDER_DEFLECTION"))); + } + if (MSFS_running_simhub) + { + Rudder_G_value_dz = ACCELERATION_BODY_Z_Simhub; + Rudder_G_value_dy = ACCELERATION_BODY_Y_Simhub; + RELATIVE_WIND_VELOCITY_BODY_Z = RELATIVE_WIND_VELOCITY_BODY_Z_Simhub; + Rudder_Radians = RUDDER_DEFLECTION_Simhub; + } + if (Settings.Rudder_ACC_WindForce) + { + + double Rudder_Wind_Force = Math.Sin(Rudder_Radians) * RELATIVE_WIND_VELOCITY_BODY_Z; + Rudder_Wind_Force_last_value = (Byte)Rudder_Wind_Force; + double Max_Wind_Force = 100; + Rudder_Wind_Force = Math.Min(Max_Wind_Force, Rudder_Wind_Force);//clipping max force + Rudder_Wind_Froce_Ratio = 0.5 * 100 * (Rudder_Wind_Force / Max_Wind_Force); + } + //G-effect + double Rudder_G_percent = 0; + double max_G = 100; + + double Rudder_G_value_combined = Math.Sqrt(Rudder_G_value_dz * Rudder_G_value_dz + Rudder_G_value_dy * Rudder_G_value_dy); + double Rudder_G_constrain = Math.Min(Rudder_G_value_combined, max_G); + Rudder_G_percent = Rudder_G_constrain / max_G * 100.0f; + double Rudder_G_Wind_combined = Math.Min(Rudder_G_percent + Rudder_Wind_Froce_Ratio, max_G); + + if (Math.Abs(Rudder_G_last_value - Rudder_G_percent) > 2) + { + tmp.payloadPedalAction_.impact_value = (Byte)Rudder_G_Wind_combined; + Rudder_Effect_update_b = true; + Rudder_Action_lastTime = DateTime.Now; + Rudder_G_last_value = (Byte)Rudder_G_Wind_combined; + } + } + + + + + //Write to Pedal + if (Rudder_Effect_update_b) + { + for (uint PIDX = 1; PIDX < 3; PIDX++) + { + tmp.payloadHeader_.PedalTag = (byte)PIDX; + DAP_action_st* v = &tmp; + byte* p = (byte*)v; + tmp.payloadFooter_.checkSum = checksumCalc(p, sizeof(payloadHeader) + sizeof(payloadPedalAction)); + int length = sizeof(DAP_action_st); + byte[] newBuffer = new byte[length]; + newBuffer = getBytes_Action(tmp); + if (ESPsync_serialPort.IsOpen) + { + ESPsync_serialPort.DiscardInBuffer(); + ESPsync_serialPort.Write(newBuffer, 0, newBuffer.Length); + System.Threading.Thread.Sleep(7); + } + } + Rudder_Effect_update_b = false; + } + } + } } - SystemSounds.Beep.Play(); + + } @@ -1091,8 +1335,8 @@ unsafe public void DataUpdate(PluginManager pluginManager, ref GameData data) pluginManager.SetPropertyValue("pedal_position", this.GetType(), pedal_state_in_ratio); pluginManager.SetPropertyValue("PedalErrorIndex", this.GetType(), PedalErrorIndex); pluginManager.SetPropertyValue("PedalErrorCode", this.GetType(), PedalErrorCode); - - + pluginManager.SetPropertyValue("FlightRudder_G", this.GetType(), Rudder_G_last_value); + pluginManager.SetPropertyValue("FlightRudder_Wind_Force", this.GetType(), Rudder_Wind_Force_last_value); } @@ -1481,7 +1725,7 @@ public void Init(PluginManager pluginManager) // Load settings Settings = this.ReadCommonSettings("GeneralSettings", () => new DataPluginDemoSettings()); - + Simhub_version = (String)pluginManager.GetPropertyValue("DataCorePlugin.SimHubVersion"); // Declare a property available in the property list, this gets evaluated "on demand" (when shown or used in formulas) //this.AttachDelegate("CurrentDateTime", () => DateTime.Now); pluginManager.AddProperty("ProfileIndex", this.GetType(), profile_index); @@ -1500,7 +1744,8 @@ public void Init(PluginManager pluginManager) pluginManager.AddProperty("pedal_position", this.GetType(), pedal_state_in_ratio); pluginManager.AddProperty("PedalErrorIndex", this.GetType(), PedalErrorIndex); pluginManager.AddProperty("PedalErrorCode", this.GetType(), PedalErrorCode); - + pluginManager.AddProperty("FlightRudder_G", this.GetType(), Rudder_G_last_value); + pluginManager.AddProperty("FlightRudder_Wind_Force", this.GetType(), Rudder_Wind_Force_last_value); for (uint pedali=0; pedali < 3; pedali++) { Action_currentTime[pedali] = new DateTime(); @@ -1508,7 +1753,18 @@ public void Init(PluginManager pluginManager) Action_lastTime[pedali] = new DateTime(); Action_lastTime[pedali] = DateTime.Now; } - + + Version inputVersion = new Version(Simhub_version); + string MSFS_Version_Above = "9.5.99"; + Version versionThreshold = new Version(MSFS_Version_Above); + if (inputVersion > versionThreshold) + { + Version_Check_Simhub_MSFS = true; + } + else + { + Version_Check_Simhub_MSFS = false; + } // Declare an event //this.AddEvent("SpeedWarning"); @@ -1750,6 +2006,7 @@ public void Init(PluginManager pluginManager) SimHub.Logging.Current.Info("Rudder Brake"); }); + /* this.AddAction("Rudder", (a, b) => { @@ -1757,6 +2014,7 @@ public void Init(PluginManager pluginManager) SimHub.Logging.Current.Info("Rudder action"); }); + */ //Settings.selectedJsonIndexLast[0] //SimHub.Logging.Current.Info("Diy active pedas plugin - Test 1"); @@ -1959,7 +2217,7 @@ public void Init(PluginManager pluginManager) dap_config_initial_st.payloadPedalConfig_.spindlePitch_mmPerRev_u8 = 5; dap_config_initial_st.payloadPedalConfig_.pedal_type = 0; //dap_config_initial_st.payloadPedalConfig_.OTA_flag = 0; - dap_config_initial_st.payloadPedalConfig_.enableReboot_u8 = 1; + dap_config_initial_st.payloadPedalConfig_.stepLossFunctionFlags_u8 = 0b11; diff --git a/SimHubPlugin/DataPluginDemoSettings.cs b/SimHubPlugin/DataPluginDemoSettings.cs index 1e6ce0f0..4806cf19 100644 --- a/SimHubPlugin/DataPluginDemoSettings.cs +++ b/SimHubPlugin/DataPluginDemoSettings.cs @@ -20,7 +20,7 @@ public class DataPluginDemoSettings public uint[] connect_flag = new uint[3] { 0, 0, 0 }; public uint RPM_effect_type = 0; public uint table_selected = 0; - public int[] auto_connect_flag = new int[3] { 0,0,0}; + public int[] auto_connect_flag = new int[3] { 0, 0, 0 }; public int[] selectedComPortNamesInt = new int[3] { -1, -1, -1 }; public int[] ABS_enable_flag = new int[3] { 0, 0, 0 }; public int[] RPM_enable_flag = new int[3] { 0, 0, 0 }; @@ -38,11 +38,11 @@ public class DataPluginDemoSettings public double kinematicDiagram_zeroPos_OX = 100; public double kinematicDiagram_zeroPos_OY = 20; public double kinematicDiagram_zeroPos_scale = 1.5; - public bool[] RTSDTR_False = new bool[3] { true,true,true}; + public bool[] RTSDTR_False = new bool[3] { true, true, true }; public bool[] USING_ESP32S3 = new bool[3] { true, true, true }; - public bool[] CV1_enable_flag = new bool[3] { false,false, false }; + public bool[] CV1_enable_flag = new bool[3] { false, false, false }; public int[] CV1_trigger = new int[3] { 0, 0, 0 }; - public string[] CV1_bindings = new string[3] { "","",""}; + public string[] CV1_bindings = new string[3] { "", "", "" }; public bool[] CV2_enable_flag = new bool[3] { false, false, false }; public int[] CV2_trigger = new int[3] { 0, 0, 0 }; public string[] CV2_bindings = new string[3] { "", "", "" }; @@ -50,9 +50,16 @@ public class DataPluginDemoSettings public bool[] Pedal_ESPNow_Sync_flag = new bool[3] { false, false, false }; public bool Pedal_ESPNow_auto_connect_flag = false; public bool Serial_auto_clean = false; //clean serial monitor + public bool Serial_auto_clean_bridge = false; //clean serial monitor bridge public bool Using_CDC_bridge = false; public byte[] Pedal_action_interval = new byte[3] { 50, 51, 53 }; - + public bool Rudder_RPM_effect_b = false; + public bool Rudder_ACC_effect_b = false; + public bool Rudder_ACC_WindForce = false; + public bool advanced_b = false; + public bool[,,] Effect_status_prolife = new bool[6, 3, 8] { { { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false } }, { { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false } }, { { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false } }, { { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false } }, { { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false } }, { { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false }, { false, false, false, false, false, false, false, false } } }; + public string SSID_string = ""; + public string PASS_string = ""; } diff --git a/SimHubPlugin/SettingsControlDemo.xaml b/SimHubPlugin/SettingsControlDemo.xaml index 1cfbe86a..638fd6c3 100644 --- a/SimHubPlugin/SettingsControlDemo.xaml +++ b/SimHubPlugin/SettingsControlDemo.xaml @@ -7,11 +7,93 @@ xmlns:styles="clr-namespace:SimHub.Plugins.Styles;assembly=SimHub.Plugins" mc:Ignorable="d" xmlns:ui="clr-namespace:SimHub.Plugins.UI;assembly=SimHub.Plugins" xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" - Height="900" Width="1110"> + Height="900" Width="1190"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -307,32 +389,22 @@ - + - + - - - - - - - - + + - - - - + + - - - + - - - - - - - + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +