├── .DS_Store ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Arduino ├── ArduinoI2C │ ├── ArduinoI2C.ino │ ├── odrive.h │ ├── odrive_endpoints.h │ └── type_traits.h └── ODriveArduino │ ├── LICENSE │ ├── ODriveArduino.cpp │ ├── ODriveArduino.h │ ├── README.md │ └── examples │ └── ODriveArduinoTest │ └── ODriveArduinoTest.ino ├── CHANGELOG.md ├── Firmware ├── .DS_Store ├── .gitignore ├── .vscode │ ├── c_cpp_properties.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── Board │ └── v3 │ │ ├── 0001-display-correct-ODrive-version-in-USB-descriptor.patch │ │ ├── 0001-expose-correct-serial-number-on-USB.patch │ │ ├── 0001-fix-return-type-of-osSemaphoreWait.patch │ │ ├── 0001-release-sem_usb_tx-in-usbd_cdc.c.patch │ │ ├── 0002-Add-I2C-files-and-settings.patch │ │ ├── 0002-FreeRTOS-constness-fixes.patch │ │ ├── 0003-disable-IRQ-for-DMA2_Stream0.patch │ │ ├── Drivers │ │ ├── CMSIS │ │ │ ├── Device │ │ │ │ └── ST │ │ │ │ │ └── STM32F4xx │ │ │ │ │ └── Include │ │ │ │ │ ├── stm32f405xx.h │ │ │ │ │ ├── stm32f4xx.h │ │ │ │ │ └── system_stm32f4xx.h │ │ │ ├── Include │ │ │ │ ├── arm_common_tables.h │ │ │ │ ├── arm_const_structs.h │ │ │ │ ├── arm_math.h │ │ │ │ ├── cmsis_armcc.h │ │ │ │ ├── cmsis_armcc_V6.h │ │ │ │ ├── cmsis_gcc.h │ │ │ │ ├── core_cm0.h │ │ │ │ ├── core_cm0plus.h │ │ │ │ ├── core_cm3.h │ │ │ │ ├── core_cm4.h │ │ │ │ ├── core_cm7.h │ │ │ │ ├── core_cmFunc.h │ │ │ │ ├── core_cmInstr.h │ │ │ │ ├── core_cmSimd.h │ │ │ │ ├── core_sc000.h │ │ │ │ └── core_sc300.h │ │ │ └── Lib │ │ │ │ └── libarm_cortexM4lf_math.a │ │ └── STM32F4xx_HAL_Driver │ │ │ ├── Inc │ │ │ ├── Legacy │ │ │ │ └── stm32_hal_legacy.h │ │ │ ├── stm32f4xx_hal.h │ │ │ ├── stm32f4xx_hal_adc.h │ │ │ ├── stm32f4xx_hal_adc_ex.h │ │ │ ├── stm32f4xx_hal_can.h │ │ │ ├── stm32f4xx_hal_cortex.h │ │ │ ├── stm32f4xx_hal_def.h │ │ │ ├── stm32f4xx_hal_dma.h │ │ │ ├── stm32f4xx_hal_dma_ex.h │ │ │ ├── stm32f4xx_hal_flash.h │ │ │ ├── stm32f4xx_hal_flash_ex.h │ │ │ ├── stm32f4xx_hal_flash_ramfunc.h │ │ │ ├── stm32f4xx_hal_gpio.h │ │ │ ├── stm32f4xx_hal_gpio_ex.h │ │ │ ├── stm32f4xx_hal_i2c.h │ │ │ ├── stm32f4xx_hal_i2c_ex.h │ │ │ ├── stm32f4xx_hal_pcd.h │ │ │ ├── stm32f4xx_hal_pcd_ex.h │ │ │ ├── stm32f4xx_hal_pwr.h │ │ │ ├── stm32f4xx_hal_pwr_ex.h │ │ │ ├── stm32f4xx_hal_rcc.h │ │ │ ├── stm32f4xx_hal_rcc_ex.h │ │ │ ├── stm32f4xx_hal_spi.h │ │ │ ├── stm32f4xx_hal_tim.h │ │ │ ├── stm32f4xx_hal_tim_ex.h │ │ │ ├── stm32f4xx_hal_uart.h │ │ │ └── stm32f4xx_ll_usb.h │ │ │ └── Src │ │ │ ├── stm32f4xx_hal.c │ │ │ ├── stm32f4xx_hal_adc.c │ │ │ ├── stm32f4xx_hal_adc_ex.c │ │ │ ├── stm32f4xx_hal_can.c │ │ │ ├── stm32f4xx_hal_cortex.c │ │ │ ├── stm32f4xx_hal_dma.c │ │ │ ├── stm32f4xx_hal_dma_ex.c │ │ │ ├── stm32f4xx_hal_flash.c │ │ │ ├── stm32f4xx_hal_flash_ex.c │ │ │ ├── stm32f4xx_hal_flash_ramfunc.c │ │ │ ├── stm32f4xx_hal_gpio.c │ │ │ ├── stm32f4xx_hal_i2c.c │ │ │ ├── stm32f4xx_hal_i2c_ex.c │ │ │ ├── stm32f4xx_hal_pcd.c │ │ │ ├── stm32f4xx_hal_pcd_ex.c │ │ │ ├── stm32f4xx_hal_pwr.c │ │ │ ├── stm32f4xx_hal_pwr_ex.c │ │ │ ├── stm32f4xx_hal_rcc.c │ │ │ ├── stm32f4xx_hal_rcc_ex.c │ │ │ ├── stm32f4xx_hal_spi.c │ │ │ ├── stm32f4xx_hal_tim.c │ │ │ ├── stm32f4xx_hal_tim_ex.c │ │ │ ├── stm32f4xx_hal_uart.c │ │ │ └── stm32f4xx_ll_usb.c │ │ ├── Inc │ │ ├── FreeRTOSConfig.h │ │ ├── adc.h │ │ ├── can.h │ │ ├── dma.h │ │ ├── freertos_vars.h │ │ ├── gpio.h │ │ ├── i2c.h │ │ ├── main.h │ │ ├── mxconstants.h │ │ ├── prev_board_ver │ │ │ ├── main_V3_2.h │ │ │ └── main_V3_4.h │ │ ├── spi.h │ │ ├── stm32f4xx_hal_conf.h │ │ ├── stm32f4xx_it.h │ │ ├── tim.h │ │ ├── usart.h │ │ ├── usb_device.h │ │ ├── usbd_cdc_if.h │ │ ├── usbd_conf.h │ │ └── usbd_desc.h │ │ ├── Makefile │ │ ├── Middlewares │ │ ├── ST │ │ │ └── STM32_USB_Device_Library │ │ │ │ ├── Class │ │ │ │ └── CDC │ │ │ │ │ ├── Inc │ │ │ │ │ └── usbd_cdc.h │ │ │ │ │ └── Src │ │ │ │ │ └── usbd_cdc.c │ │ │ │ └── Core │ │ │ │ ├── Inc │ │ │ │ ├── usbd_core.h │ │ │ │ ├── usbd_ctlreq.h │ │ │ │ ├── usbd_def.h │ │ │ │ └── usbd_ioreq.h │ │ │ │ └── Src │ │ │ │ ├── usbd_core.c │ │ │ │ ├── usbd_ctlreq.c │ │ │ │ └── usbd_ioreq.c │ │ └── Third_Party │ │ │ └── FreeRTOS │ │ │ └── Source │ │ │ ├── CMSIS_RTOS │ │ │ ├── cmsis_os.c │ │ │ └── cmsis_os.h │ │ │ ├── croutine.c │ │ │ ├── event_groups.c │ │ │ ├── include │ │ │ ├── FreeRTOS.h │ │ │ ├── FreeRTOSConfig_template.h │ │ │ ├── StackMacros.h │ │ │ ├── croutine.h │ │ │ ├── deprecated_definitions.h │ │ │ ├── event_groups.h │ │ │ ├── list.h │ │ │ ├── mpu_prototypes.h │ │ │ ├── mpu_wrappers.h │ │ │ ├── portable.h │ │ │ ├── projdefs.h │ │ │ ├── queue.h │ │ │ ├── semphr.h │ │ │ ├── task.h │ │ │ └── timers.h │ │ │ ├── list.c │ │ │ ├── portable │ │ │ ├── GCC │ │ │ │ └── ARM_CM4F │ │ │ │ │ ├── port.c │ │ │ │ │ └── portmacro.h │ │ │ └── MemMang │ │ │ │ └── heap_4.c │ │ │ ├── queue.c │ │ │ ├── tasks.c │ │ │ └── timers.c │ │ ├── Odrive.ioc │ │ ├── STM32F405RGTx_FLASH.ld │ │ ├── Src │ │ ├── adc.c │ │ ├── can.c │ │ ├── dma.c │ │ ├── freertos.c │ │ ├── gpio.c │ │ ├── i2c.c │ │ ├── main.c │ │ ├── prev_board_ver │ │ │ ├── adc_V3_2.c │ │ │ ├── adc_V3_4.c │ │ │ ├── gpio_V3_2.c │ │ │ └── gpio_V3_4.c │ │ ├── spi.c │ │ ├── stm32f4xx_hal_msp.c │ │ ├── stm32f4xx_hal_timebase_TIM.c │ │ ├── stm32f4xx_it.c │ │ ├── syscalls.c │ │ ├── system_stm32f4xx.c │ │ ├── tim.c │ │ ├── usart.c │ │ ├── usb_device.c │ │ ├── usbd_cdc_if.c │ │ ├── usbd_conf.c │ │ └── usbd_desc.c │ │ └── startup_stm32f405xx.s ├── Drivers │ └── DRV8301 │ │ ├── drv8301.c │ │ └── drv8301.h ├── FreeRTOS-openocd.c ├── LICENSE ├── Makefile ├── MotorControl │ ├── axis.cpp │ ├── axis.hpp │ ├── board_config_v3.h │ ├── controller.cpp │ ├── controller.hpp │ ├── encoder.cpp │ ├── encoder.hpp │ ├── example.json │ ├── low_level.cpp │ ├── low_level.h │ ├── main.cpp │ ├── motor.cpp │ ├── motor.hpp │ ├── nvm.c │ ├── nvm.h │ ├── nvm_config.hpp │ ├── odrive_main.h │ ├── sensorless_estimator.cpp │ ├── sensorless_estimator.hpp │ ├── utils.c │ └── utils.h ├── ODriveFirmware.launch ├── Tupfile.ini ├── Tupfile.lua ├── adctest.py ├── build.lua ├── build.sh ├── communication │ ├── ascii_protocol.cpp │ ├── ascii_protocol.hpp │ ├── communication.cpp │ ├── communication.h │ ├── interface_can.cpp │ ├── interface_can.hpp │ ├── interface_i2c.cpp │ ├── interface_i2c.h │ ├── interface_uart.cpp │ ├── interface_uart.h │ ├── interface_usb.cpp │ └── interface_usb.h ├── fibre │ ├── .gitignore │ ├── README.md │ ├── cpp │ │ ├── include │ │ │ └── fibre │ │ │ │ ├── cpp_utils.hpp │ │ │ │ ├── crc.hpp │ │ │ │ ├── decoders.hpp │ │ │ │ ├── encoders.hpp │ │ │ │ ├── posix_tcp.hpp │ │ │ │ ├── posix_udp.hpp │ │ │ │ └── protocol.hpp │ │ ├── package.lua │ │ ├── posix_tcp.cpp │ │ ├── posix_udp.cpp │ │ └── protocol.cpp │ ├── python │ │ ├── .gitignore │ │ ├── fibre │ │ │ ├── __init__.py │ │ │ ├── discovery.py │ │ │ ├── protocol.py │ │ │ ├── remote_object.py │ │ │ ├── serial_transport.py │ │ │ ├── shell.py │ │ │ ├── tcp_transport.py │ │ │ ├── udp_transport.py │ │ │ ├── usbbulk_transport.py │ │ │ └── utils.py │ │ └── setup.py │ ├── test │ │ ├── Tupfile.lua │ │ ├── run_tests.cpp │ │ └── test_server.cpp │ ├── tools │ │ └── fibre-shell │ └── tupfiles │ │ └── build.lua ├── find_programmer.sh ├── motor_timing.jpg ├── openocd.gdbinit └── tup.config.default ├── ODrive_Workspace.code-workspace ├── README.md ├── analysis ├── cogging_torque │ └── cogging_harmonics.py ├── motor_analysis │ ├── 350kvTP.PNG │ ├── 350kvVelli.PNG │ └── VelliPlot.m └── numeric_path_opt │ ├── Main.m │ └── predictionmatrices.m ├── docs ├── CNAME ├── Gemfile ├── Gemfile.lock ├── _config.yaml ├── _data │ └── index.yaml ├── _layouts │ └── default.html ├── ascii-protocol.md ├── assets │ └── css │ │ └── style.scss ├── commands.md ├── configuring-eclipse.md ├── configuring-vscode.md ├── developer-guide.md ├── encoders.md ├── favicon.ico ├── getting-started.md ├── interfaces.md ├── odrivetool.md ├── protocol.md ├── screenshots │ ├── CodeAsMakefile.png │ ├── ImportLaunch.png │ └── LaunchConfigFilter.png ├── stlink-wiring-cropped.jpg ├── test.md ├── testing.md └── troubleshooting.md └── tools ├── .gitignore ├── .vscode └── launch.json ├── bandwidthtest.py ├── doggo_setup.py ├── odrive ├── __init__.py ├── code_generator.py ├── configuration.py ├── dfu.py ├── dfuse │ ├── COPYING │ ├── DfuDevice.py │ ├── DfuFile.py │ ├── DfuState.py │ ├── DfuStatus.py │ └── __init__.py ├── enums.py ├── shell.py ├── tests.py ├── utils.py └── version.py ├── odrive_demo.py ├── odrive_header_template.h.in ├── odrivetool ├── odrivetool.bat ├── requirements.txt ├── run_tests.py ├── save_config_issue_example.py ├── setup.py ├── test-rig-loopback.yaml ├── test-rig-parallel.yaml ├── usbpermission └── woofer_setup.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Unit test / coverage reports 10 | htmlcov/ 11 | .tox/ 12 | .coverage 13 | .coverage.* 14 | .cache 15 | nosetests.xml 16 | coverage.xml 17 | *,cover 18 | .hypothesis/ 19 | 20 | # Translations 21 | *.mo 22 | *.pot 23 | 24 | # Django stuff: 25 | *.log 26 | 27 | # Sphinx documentation 28 | docs/_build/ 29 | 30 | # PyBuilder 31 | target/ 32 | 33 | #Ipython Notebook 34 | .ipynb_checkpoints 35 | 36 | # Tup 37 | .tup 38 | tup.config 39 | 40 | /ruby-bundle 41 | /_site 42 | /.bundle 43 | 44 | bin 45 | tools/.DS_Store 46 | tools/.vscode/DONTUSElaunch.json -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/.gitmodules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # adapted from https://github.com/andysworkshop/stm32plus/blob/master/.travis.yml 2 | 3 | branches: 4 | only: 5 | - master 6 | - devel 7 | - /^fw-v/ 8 | 9 | language: c 10 | sudo: false 11 | 12 | addons: 13 | apt: 14 | packages: 15 | libc6-i386 16 | 17 | cache: 18 | directories: 19 | - "$HOME/dl" 20 | 21 | install: 22 | # - export GCC_DIR=$HOME/dl/gcc-arm-none-eabi-5_2-2015q4 23 | # - export GCC_ARCHIVE=$HOME/dl/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 24 | # - export GCC_URL=https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 25 | # - if [ ! -e $GCC_DIR/bin/arm-none-eabi-gcc ]; then wget $GCC_URL -O $GCC_ARCHIVE; tar xfj $GCC_ARCHIVE -C $HOME/dl; fi 26 | # - export PATH=$PATH:$GCC_DIR/bin 27 | 28 | - export GCC_DIR=$HOME/dl/gcc-arm-none-eabi-7-2017-q4-major 29 | - export GCC_ARCHIVE=$HOME/dl/gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2 30 | - export GCC_URL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2017q4/gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2 31 | - if [ ! -e $GCC_DIR/bin/arm-none-eabi-gcc ]; then wget $GCC_URL -O $GCC_ARCHIVE; tar xfj $GCC_ARCHIVE -C $HOME/dl; fi 32 | - export PATH=$PATH:$GCC_DIR/bin 33 | 34 | - export TUP_DIR=$HOME/dl/tup_0.7.5-0~16.04.york0_amd64 35 | - export TUP_ARCHIVE=$HOME/dl/tup_0.7.5-0~16.04.york0_amd64.deb 36 | - export TUP_URL=http://ppa.launchpad.net/jonathonf/tup/ubuntu/pool/main/t/tup/tup_0.7.5-0~16.04.york0_amd64.deb 37 | - if [ ! -e $TUP_DIR/bin/tup ]; then wget $TUP_URL -O $TUP_ARCHIVE; dpkg-deb -R $TUP_ARCHIVE $TUP_DIR; fi 38 | - export PATH=$PATH:$TUP_DIR/usr/bin 39 | 40 | env: 41 | # Build default configuration for each board 42 | - CONFIG_BOARD_VERSION=v3.2 DEPLOY=v3.2 43 | - CONFIG_BOARD_VERSION=v3.3 DEPLOY=v3.3 44 | - CONFIG_BOARD_VERSION=v3.4-24V DEPLOY=v3.4-24V 45 | - CONFIG_BOARD_VERSION=v3.4-48V DEPLOY=v3.4-48V 46 | - CONFIG_BOARD_VERSION=v3.5-24V DEPLOY=v3.5-24V 47 | - CONFIG_BOARD_VERSION=v3.5-48V DEPLOY=v3.5-48V 48 | 49 | # Various protocol combinations 50 | - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=native-stream CONFIG_UART_PROTOCOL=native 51 | - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=stdout CONFIG_UART_PROTOCOL=stdout 52 | - CONFIG_BOARD_VERSION=v3.4-24V CONFIG_USB_PROTOCOL=none CONFIG_UART_PROTOCOL=none 53 | 54 | script: 55 | - "./Firmware/build.sh" 56 | 57 | deploy: 58 | provider: releases 59 | api_key: 60 | secure: RM66joGTn11Z5PmG7Nlj8cRcVY0w7ga5qUl2ahinbDm6jMV8OxroaXKivEa478alx9fygMHVeKdJZUlrAkRJ5OYJ1trfpW+43S3OYEnfy1nyXEXRwhgeIlb9LqdrumXVAp7TZ0Vppfom8A2ZWbxKxW3lG/EAmA4G9fnxHf0S9rF0y95YVfGrxdapTKcxvbP7Yojo53474ZI6+VYrqx8lq0JAnn4FwNT9ZJ1QASrmIw4w08f60XXv25BzndCTscvLb2qUu0AaGLbQUosde0Bb7P+aQsBVY6uSkg9MWV8gWPQjtO3u5IRR1bTshxf2kPqtzwK+SpcYrddoGN6BkKAB3lVorJIW5VguUkRmtPZ1K9+NhIztNevB2qr0ASutumNLF3aqMt19KL3A+SRx6froj5VhRHf4i/Xjm3SDLTaTcc8ZIh2PEE6scUMUMs5Mzu8LQWjInRe25MSb+pQB1mNOHmoFBtVb0J3u7Nvs8jdImN5gQWvvowWXfXRNE0ncT1YsLmevwi3q+YdEjpAIPnrD/rouY8WaqQZ/vE15JM9uwdQRqKAbzGtMaKHDk7EZ7ANTyaP+UrQ/M5cVDa0bWsWSvqSqDJMy4IVHRlirYA/5u74lXNhmA8DGDB/gFVlVCmoEzas/pnYiAE1hh4RpsYxts78Ix+wbeo1hmt7t65X8cyo= 61 | skip_cleanup: true 62 | file_glob: true 63 | file: Firmware/deploy/* 64 | on: 65 | repo: madcowswe/ODrive 66 | branch: master 67 | tags: true 68 | -------------------------------------------------------------------------------- /Arduino/ODriveArduino/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Oskar Weigl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Arduino/ODriveArduino/ODriveArduino.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Arduino.h" 3 | #include "ODriveArduino.h" 4 | 5 | static const int kMotorOffsetFloat = 2; 6 | static const int kMotorStrideFloat = 28; 7 | static const int kMotorOffsetInt32 = 0; 8 | static const int kMotorStrideInt32 = 4; 9 | static const int kMotorOffsetBool = 0; 10 | static const int kMotorStrideBool = 4; 11 | static const int kMotorOffsetUint16 = 0; 12 | static const int kMotorStrideUint16 = 2; 13 | 14 | // Print with stream operator 15 | template inline Print& operator <<(Print &obj, T arg) { obj.print(arg); return obj; } 16 | template<> inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; } 17 | 18 | ODriveArduino::ODriveArduino(Stream& serial) 19 | : serial_(serial) {} 20 | 21 | void ODriveArduino::SetPosition(int motor_number, float position) { 22 | SetPosition(motor_number, position, 0.0f, 0.0f); 23 | } 24 | 25 | void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward) { 26 | SetPosition(motor_number, position, velocity_feedforward, 0.0f); 27 | } 28 | 29 | void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward) { 30 | serial_ << "p " << motor_number << " " << position << " " << velocity_feedforward << " " << current_feedforward << "\n"; 31 | } 32 | 33 | void ODriveArduino::SetVelocity(int motor_number, float velocity) { 34 | SetVelocity(motor_number, velocity, 0.0f); 35 | } 36 | 37 | void ODriveArduino::SetVelocity(int motor_number, float velocity, float current_feedforward) { 38 | serial_ << "v " << motor_number << " " << velocity << " " << current_feedforward << "\n"; 39 | } 40 | 41 | float ODriveArduino::readFloat() { 42 | return readString().toFloat(); 43 | } 44 | 45 | int32_t ODriveArduino::readInt() { 46 | return readString().toInt(); 47 | } 48 | 49 | bool ODriveArduino::run_state(int axis, int requested_state, bool wait) { 50 | int timeout_ctr = 100; 51 | serial_ << "w axis" << axis << ".requested_state " << requested_state << '\n'; 52 | if (wait) { 53 | do { 54 | delay(100); 55 | serial_ << "r axis" << axis << ".current_state\n"; 56 | } while (readInt() != AXIS_STATE_IDLE && --timeout_ctr > 0); 57 | } 58 | 59 | return timeout_ctr > 0; 60 | } 61 | 62 | String ODriveArduino::readString() { 63 | String str = ""; 64 | static const unsigned long timeout = 1000; 65 | unsigned long timeout_start = millis(); 66 | for (;;) { 67 | while (!serial_.available()) { 68 | if (millis() - timeout_start >= timeout) { 69 | return str; 70 | } 71 | } 72 | char c = serial_.read(); 73 | if (c == '\n') 74 | break; 75 | str += c; 76 | } 77 | return str; 78 | } 79 | -------------------------------------------------------------------------------- /Arduino/ODriveArduino/ODriveArduino.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ODriveArduino_h 3 | #define ODriveArduino_h 4 | 5 | #include "Arduino.h" 6 | 7 | class ODriveArduino { 8 | public: 9 | enum AxisState_t { 10 | AXIS_STATE_UNDEFINED = 0, // Include Library -> Add .ZIP Library...* 5 | 6 | Select the enclosing folder (e.g. ODriveArduino) to add it. Restarting the Arduino IDE may be necessary to see the examples in the *File* dropdown. Check the included example *ODriveArduinoTest* for basic usage. 7 | -------------------------------------------------------------------------------- /Arduino/ODriveArduino/examples/ODriveArduinoTest/ODriveArduinoTest.ino: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | // Printing with stream operator 6 | template inline Print& operator <<(Print &obj, T arg) { obj.print(arg); return obj; } 7 | template<> inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; } 8 | 9 | // Serial to the ODrive 10 | SoftwareSerial odrive_serial(8, 9); //RX (ODrive TX), TX (ODrive RX) 11 | 12 | // ODrive object 13 | ODriveArduino odrive(odrive_serial); 14 | 15 | void setup() { 16 | // ODrive uses 115200 baud 17 | odrive_serial.begin(115200); 18 | 19 | // Serial to PC 20 | Serial.begin(115200); 21 | while (!Serial) ; // wait for Arduino Serial Monitor to open 22 | 23 | Serial.println("ODriveArduino"); 24 | Serial.println("Setting parameters..."); 25 | 26 | // In this example we set the same parameters to both motors. 27 | // You can of course set them different if you want. 28 | // See the documentation or play around in odrivetool to see the available parameters 29 | for (int axis = 0; axis < 2; ++axis) { 30 | odrive_serial << "w axis" << axis << ".controller.config.vel_limit " << 22000.0f << '\n'; 31 | odrive_serial << "w axis" << axis << ".motor.config.current_lim " << 11.0f << '\n'; 32 | // This ends up writing something like "w axis0.motor.config.current_lim 10.0\n" 33 | } 34 | 35 | Serial.println("Ready!"); 36 | Serial.println("Send the character '0' or '1' to calibrate respective motor (you must do this before you can command movement)"); 37 | Serial.println("Send the character 's' to exectue test move"); 38 | Serial.println("Send the character 'b' to read bus voltage"); 39 | Serial.println("Send the character 'p' to read motor positions in a 10s loop"); 40 | } 41 | 42 | void loop() { 43 | 44 | if (Serial.available()) { 45 | char c = Serial.read(); 46 | 47 | // Run calibration sequence 48 | if (c == '0' || c == '1') { 49 | int requested_state; 50 | 51 | requested_state = ODriveArduino::AXIS_STATE_MOTOR_CALIBRATION; 52 | Serial << "Axis" << c << ": Requesting state " << requested_state << '\n'; 53 | odrive.run_state(atoi(c), requested_state, true); 54 | 55 | requested_state = ODriveArduino::AXIS_STATE_ENCODER_OFFSET_CALIBRATION; 56 | Serial << "Axis" << c << ": Requesting state " << requested_state << '\n'; 57 | odrive.run_state(atoi(c), requested_state, true); 58 | 59 | requested_state = ODriveArduino::AXIS_STATE_CLOSED_LOOP_CONTROL; 60 | Serial << "Axis" << c << ": Requesting state " << requested_state << '\n'; 61 | odrive.run_state(atoi(c), requested_state, false); // don't wait 62 | } 63 | 64 | // Sinusoidal test move 65 | if (c == 's') { 66 | Serial.println("Executing test move"); 67 | for (float ph = 0.0f; ph < 6.28318530718f; ph += 0.01f) { 68 | float pos_m0 = 20000.0f * cos(ph); 69 | float pos_m1 = 20000.0f * sin(ph); 70 | odrive.SetPosition(0, pos_m0); 71 | odrive.SetPosition(1, pos_m1); 72 | delay(5); 73 | } 74 | } 75 | 76 | // Read bus voltage 77 | if (c == 'b') { 78 | odrive_serial << "r vbus_voltage\n"; 79 | Serial << "Vbus voltage: " << odrive.readFloat() << '\n'; 80 | } 81 | 82 | // print motor positions in a 10s loop 83 | if (c == 'p') { 84 | static const unsigned long duration = 10000; 85 | unsigned long start = millis(); 86 | while(millis() - start < duration) { 87 | for (int motor = 0; motor < 2; ++motor) { 88 | odrive_serial << "r axis" << motor << ".encoder.pos_estimate\n"; 89 | Serial << odrive.readFloat() << '\t'; 90 | } 91 | Serial << '\n'; 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Firmware/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/.DS_Store -------------------------------------------------------------------------------- /Firmware/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #build folder 3 | build/ 4 | deploy/ 5 | .dep/ 6 | tup_build.sh 7 | 8 | #markdown preview output 9 | README.html 10 | 11 | #autogenerated project files 12 | .cproject 13 | .mxproject 14 | Odrive.xml 15 | 16 | #Eclipse stuff 17 | .settings/ 18 | .project 19 | 20 | # VSCode stuff 21 | /.vscode/.cortex-debug.*.state.json 22 | 23 | # STM32CubeMX (in case you put it in this folder, or a symlink) 24 | STM32CubeMX 25 | 26 | #gdb log 27 | openocd.log 28 | -------------------------------------------------------------------------------- /Firmware/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | // For the Cortex-Debug extension 9 | "type": "cortex-debug", 10 | "servertype": "openocd", 11 | "request": "launch", 12 | "name": "Debug ODrive", 13 | "executable": "${workspaceRoot}/build/ODriveFirmware.elf", 14 | "configFiles": [ 15 | "interface/stlink-v2.cfg", 16 | "target/stm32f4x_stlink.cfg", 17 | ], 18 | "cwd": "${workspaceRoot}" 19 | }, 20 | { 21 | // For the Cortex-Debug extension 22 | "type": "cortex-debug", 23 | "servertype": "openocd", 24 | "request": "launch", 25 | "name": "Debug ODrive - FreeRTOS", 26 | "executable": "${workspaceRoot}/build/ODriveFirmware.elf", 27 | "rtos": "FreeRTOS", 28 | "configFiles": [ 29 | "interface/stlink-v2.cfg", 30 | "target/stm32f4x_stlink.cfg", 31 | ], 32 | "cwd": "${workspaceRoot}" 33 | }, 34 | ] 35 | } -------------------------------------------------------------------------------- /Firmware/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.clang_format_style": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0 }", 3 | "C_Cpp.intelliSenseEngine": "Default", 4 | "C_Cpp.intelliSenseEngineFallback": "Disabled", 5 | "files.exclude": { 6 | "build": true 7 | }, 8 | "files.associations": { 9 | "memory": "cpp", 10 | "utility": "cpp", 11 | "deque": "cpp", 12 | "vector": "cpp", 13 | "array": "cpp", 14 | "*.tcc": "cpp", 15 | "cctype": "cpp", 16 | "clocale": "cpp", 17 | "cstdint": "cpp", 18 | "cstdio": "cpp", 19 | "cstdlib": "cpp", 20 | "cstring": "cpp", 21 | "cwchar": "cpp", 22 | "cwctype": "cpp", 23 | "exception": "cpp", 24 | "functional": "cpp", 25 | "initializer_list": "cpp", 26 | "iosfwd": "cpp", 27 | "istream": "cpp", 28 | "limits": "cpp", 29 | "new": "cpp", 30 | "ostream": "cpp", 31 | "stdexcept": "cpp", 32 | "streambuf": "cpp", 33 | "string_view": "cpp", 34 | "system_error": "cpp", 35 | "tuple": "cpp", 36 | "type_traits": "cpp", 37 | "typeinfo": "cpp", 38 | "algorithm": "cpp" 39 | } 40 | } -------------------------------------------------------------------------------- /Firmware/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "type": "shell", 9 | "command": "make", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "panel": "new" 16 | }, 17 | "problemMatcher": [ 18 | "$gcc" 19 | ] 20 | }, 21 | { 22 | "taskName": "flash", 23 | "type": "shell", 24 | "command": "make flash", 25 | "problemMatcher": [] 26 | }, 27 | { 28 | "taskName": "openocd", 29 | "type": "shell", 30 | "command": "openocd -f \"interface/stlink-v2.cfg\" -f \"target/stm32f4x_stlink.cfg\" -c \"gdb_port 3333; log_output openocd.log\"", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /Firmware/Board/v3/0001-display-correct-ODrive-version-in-USB-descriptor.patch: -------------------------------------------------------------------------------- 1 | From b7ea3f500fbfc187a0a7112282ae6b1eee4555d0 Mon Sep 17 00:00:00 2001 2 | From: Samuel Sadok 3 | Date: Tue, 13 Mar 2018 20:05:07 -0700 4 | Subject: [PATCH] display correct ODrive version in USB descriptor 5 | 6 | --- 7 | Firmware/Board/v3/Src/usbd_desc.c | 8 +++++--- 8 | 1 file changed, 5 insertions(+), 3 deletions(-) 9 | 10 | diff --git a/Firmware/Board/v3/Src/usbd_desc.c b/Firmware/Board/v3/Src/usbd_desc.c 11 | index 94dc49b..37b4302 100644 12 | --- a/Firmware/Board/v3/Src/usbd_desc.c 13 | +++ b/Firmware/Board/v3/Src/usbd_desc.c 14 | @@ -96,7 +96,9 @@ 15 | #define USBD_LANGID_STRING 1033 16 | #define USBD_MANUFACTURER_STRING "ODrive Robotics" 17 | #define USBD_PID_FS 0x0D32 18 | -#define USBD_PRODUCT_STRING_FS "ODrive v3.3" 19 | +#define USBD_PRODUCT_XSTR(s) USBD_PRODUCT_STR(s) 20 | +#define USBD_PRODUCT_STR(s) #s 21 | +#define USBD_PRODUCT_STRING_FS ODrive version HW_VERSION_MAJOR.HW_VERSION_MINOR 22 | #define USBD_SERIALNUMBER_STRING_FS "000000000001" 23 | #define USBD_CONFIGURATION_STRING_FS "CDC Config" 24 | #define USBD_INTERFACE_STRING_FS "CDC Interface" 25 | @@ -299,11 +301,11 @@ uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length 26 | { 27 | if(speed == 0) 28 | { 29 | - USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length); 30 | + USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(USBD_PRODUCT_STRING_FS), USBD_StrDesc, length); 31 | } 32 | else 33 | { 34 | - USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length); 35 | + USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(USBD_PRODUCT_STRING_FS), USBD_StrDesc, length); 36 | } 37 | return USBD_StrDesc; 38 | } 39 | -- 40 | 2.16.2 41 | 42 | -------------------------------------------------------------------------------- /Firmware/Board/v3/0001-expose-correct-serial-number-on-USB.patch: -------------------------------------------------------------------------------- 1 | From 0867a92f742b312a0ebaafe94cade6f57be22170 Mon Sep 17 00:00:00 2001 2 | From: Samuel Sadok 3 | Date: Mon, 12 Mar 2018 23:49:32 -0700 4 | Subject: [PATCH] expose correct serial number on USB 5 | 6 | --- 7 | Firmware/Board/v3/Src/usbd_desc.c | 9 +++++++++------- 8 | 1 file changed, 1 insertions(+), 8 deletions(-) 9 | 10 | diff --git a/Firmware/Board/v3/Src/usbd_desc.c b/Firmware/Board/v3/Src/usbd_desc.c 11 | index b9c7bd0..94dc49b 100644 12 | --- a/Firmware/Board/v3/Src/usbd_desc.c 13 | +++ b/Firmware/Board/v3/Src/usbd_desc.c 14 | @@ -327,14 +327,7 @@ uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *l 15 | */ 16 | uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) 17 | { 18 | - if(speed == USBD_SPEED_HIGH) 19 | - { 20 | - USBD_GetString((uint8_t *)USBD_SERIALNUMBER_STRING_FS, USBD_StrDesc, length); 21 | - } 22 | - else 23 | - { 24 | - USBD_GetString((uint8_t *)USBD_SERIALNUMBER_STRING_FS, USBD_StrDesc, length); 25 | - } 26 | + USBD_GetString ((uint8_t *)serial_number_str, USBD_StrDesc, length); 27 | return USBD_StrDesc; 28 | } 29 | 30 | -- 31 | 2.16.2 32 | 33 | -------------------------------------------------------------------------------- /Firmware/Board/v3/0001-fix-return-type-of-osSemaphoreWait.patch: -------------------------------------------------------------------------------- 1 | From 49353ccb7023c02c2bc6e3b6f14fac02a13fe599 Mon Sep 17 00:00:00 2001 2 | From: Samuel Sadok 3 | Date: Mon, 26 Feb 2018 14:55:17 -0800 4 | Subject: [PATCH] fix return type of osSemaphoreWait 5 | 6 | --- 7 | .../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c | 6 +++--- 8 | .../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h | 6 +++--- 9 | 2 files changed, 6 insertions(+), 6 deletions(-) 10 | 11 | diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c 12 | index d0e0fd7..e764cbc 100644 13 | --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c 14 | +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c 15 | @@ -816,10 +816,10 @@ osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t 16 | * @brief Wait until a Semaphore token becomes available 17 | * @param semaphore_id semaphore object referenced with \ref osSemaphore. 18 | * @param millisec timeout value or 0 in case of no time-out. 19 | -* @retval number of available tokens, or -1 in case of incorrect parameters. 20 | +* @retval status code that indicates the execution status of the function. 21 | * @note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS. 22 | */ 23 | -int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) 24 | +osStatus osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) 25 | { 26 | TickType_t ticks; 27 | portBASE_TYPE taskWoken = pdFALSE; 28 | diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h 29 | index 15e25b9..5223f8e 100644 30 | --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h 31 | +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h 32 | @@ -719,9 +719,9 @@ osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t 33 | /// Wait until a Semaphore token becomes available. 34 | /// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate. 35 | /// \param[in] millisec timeout value or 0 in case of no time-out. 36 | -/// \return number of available tokens, or -1 in case of incorrect parameters. 37 | +/// \return status code that indicates the execution status of the function. 38 | /// \note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS. 39 | -int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec); 40 | +osStatus osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec); 41 | 42 | /// Release a Semaphore token. 43 | /// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate. 44 | -- 45 | 2.16.1 46 | 47 | -------------------------------------------------------------------------------- /Firmware/Board/v3/0001-release-sem_usb_tx-in-usbd_cdc.c.patch: -------------------------------------------------------------------------------- 1 | From 965f7f2c80e30d7a66dcac7abaa9bdc371d9ea51 Mon Sep 17 00:00:00 2001 2 | From: Samuel Sadok 3 | Date: Mon, 26 Feb 2018 14:53:52 -0800 4 | Subject: [PATCH] release sem_usb_tx in usbd_cdc.c 5 | 6 | --- 7 | .../Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c | 5 +++-- 8 | 1 file changed, 3 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/Firmware/Board/v3.3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c 11 | index b2ca5f1..6ae33e8 100644 12 | --- a/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c 13 | +++ b/Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c 14 | @@ -62,7 +62,8 @@ 15 | #include "usbd_cdc.h" 16 | #include "usbd_desc.h" 17 | #include "usbd_ctlreq.h" 18 | - 19 | +#include 20 | +#include 21 | 22 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 23 | * @{ 24 | @@ -669,7 +670,7 @@ static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) 25 | { 26 | 27 | hcdc->TxState = 0; 28 | - 29 | + osSemaphoreRelease(sem_usb_tx); 30 | return USBD_OK; 31 | } 32 | else 33 | -- 34 | 2.16.1 35 | 36 | -------------------------------------------------------------------------------- /Firmware/Board/v3/0002-FreeRTOS-constness-fixes.patch: -------------------------------------------------------------------------------- 1 | From 510ead2b159e1d8116e5241066c54a7bf8b7bfbe Mon Sep 17 00:00:00 2001 2 | From: Samuel Sadok 3 | Date: Mon, 26 Mar 2018 15:29:44 -0700 4 | Subject: [PATCH] FreeRTOS constness fixes 5 | 6 | - make thread names const char * 7 | - make thread argument non-const void* 8 | --- 9 | .../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h | 6 +++--- 10 | Firmware/Board/v3/Src/freertos.c | 4 ++-- 11 | 2 files changed, 5 insertions(+), 5 deletions(-) 12 | 13 | diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h 14 | index 09cdf27..754be24 100644 15 | --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h 16 | +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h 17 | @@ -270,11 +270,11 @@ typedef enum { 18 | 19 | /// Entry point of a thread. 20 | /// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS. 21 | -typedef void (*os_pthread) (void const *argument); 22 | +typedef void (*os_pthread) (void *argument); 23 | 24 | /// Entry point of a timer call back function. 25 | /// \note MUST REMAIN UNCHANGED: \b os_ptimer shall be consistent in every CMSIS-RTOS. 26 | -typedef void (*os_ptimer) (void const *argument); 27 | +typedef void (*os_ptimer) (void *argument); 28 | 29 | // >>> the following data type definitions may shall adapted towards a specific RTOS 30 | 31 | @@ -323,7 +323,7 @@ typedef StaticQueue_t osStaticMessageQDef_t; 32 | /// Thread Definition structure contains startup information of a thread. 33 | /// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS. 34 | typedef struct os_thread_def { 35 | - char *name; ///< Thread name 36 | + const char *name; ///< Thread name 37 | os_pthread pthread; ///< start address of thread function 38 | osPriority tpriority; ///< initial thread priority 39 | uint32_t instances; ///< maximum number of instances of that thread function 40 | diff --git a/Firmware/Board/v3/Src/freertos.c b/Firmware/Board/v3/Src/freertos.c 41 | index 6eaea82..b247994 100644 42 | --- a/Firmware/Board/v3/Src/freertos.c 43 | +++ b/Firmware/Board/v3/Src/freertos.c 44 | @@ -75,7 +75,7 @@ uint8_t ucHeap[configTOTAL_HEAP_SIZE]; 45 | /* USER CODE END Variables */ 46 | 47 | /* Function prototypes -------------------------------------------------------*/ 48 | -void StartDefaultTask(void const * argument); 49 | +void StartDefaultTask(void * argument); 50 | 51 | extern void MX_USB_DEVICE_Init(void); 52 | void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ 53 | @@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) { 54 | } 55 | 56 | /* StartDefaultTask function */ 57 | -void StartDefaultTask(void const * argument) 58 | +void StartDefaultTask(void * argument) 59 | { 60 | /* init code for USB_DEVICE */ 61 | MX_USB_DEVICE_Init(); 62 | -- 63 | 2.16.2 64 | 65 | -------------------------------------------------------------------------------- /Firmware/Board/v3/0003-disable-IRQ-for-DMA2_Stream0.patch: -------------------------------------------------------------------------------- 1 | From ab5ca860b3729d76a9c43c485776147ab69d2342 Mon Sep 17 00:00:00 2001 2 | From: Samuel Sadok 3 | Date: Mon, 26 Mar 2018 19:02:45 -0700 4 | Subject: [PATCH] disable IRQ for DMA2_Stream0 5 | 6 | This DMA stream is used to read values from ADC1 7 | while ADC1 cycles through it's sequence of input 8 | channels. No interrupts are required to make 9 | this work. 10 | --- 11 | Firmware/Board/v3/Src/dma.c | 6 ++++-- 12 | 1 file changed, 4 insertions(+), 2 deletions(-) 13 | 14 | diff --git a/Firmware/Board/v3/Src/dma.c b/Firmware/Board/v3/Src/dma.c 15 | index 55d5e03..3de873a 100644 16 | --- a/Firmware/Board/v3/Src/dma.c 17 | +++ b/Firmware/Board/v3/Src/dma.c 18 | @@ -78,8 +78,10 @@ void MX_DMA_Init(void) 19 | HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0); 20 | HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); 21 | /* DMA2_Stream0_IRQn interrupt configuration */ 22 | - HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0); 23 | - HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); 24 | + // Dear STM, no we _don't_ want to fire an interrupt for this DMA 25 | + // (it's not possible to deselect this in CubeMX) 26 | + //HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0); 27 | + //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); 28 | 29 | } 30 | 31 | -- 32 | 2.16.2 33 | 34 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/Board/v3/Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h -------------------------------------------------------------------------------- /Firmware/Board/v3/Drivers/CMSIS/Include/core_cmFunc.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file core_cmFunc.h 3 | * @brief CMSIS Cortex-M Core Function Access Header File 4 | * @version V4.30 5 | * @date 20. October 2015 6 | ******************************************************************************/ 7 | /* Copyright (c) 2009 - 2015 ARM LIMITED 8 | 9 | All rights reserved. 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | - Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | - Neither the name of ARM nor the names of its contributors may be used 18 | to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | * 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | ---------------------------------------------------------------------------*/ 33 | 34 | 35 | #if defined ( __ICCARM__ ) 36 | #pragma system_include /* treat file as system include file for MISRA check */ 37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 38 | #pragma clang system_header /* treat file as system include file */ 39 | #endif 40 | 41 | #ifndef __CORE_CMFUNC_H 42 | #define __CORE_CMFUNC_H 43 | 44 | 45 | /* ########################### Core Function Access ########################### */ 46 | /** \ingroup CMSIS_Core_FunctionInterface 47 | \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions 48 | @{ 49 | */ 50 | 51 | /*------------------ RealView Compiler -----------------*/ 52 | #if defined ( __CC_ARM ) 53 | #include "cmsis_armcc.h" 54 | 55 | /*------------------ ARM Compiler V6 -------------------*/ 56 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 57 | #include "cmsis_armcc_V6.h" 58 | 59 | /*------------------ GNU Compiler ----------------------*/ 60 | #elif defined ( __GNUC__ ) 61 | #include "cmsis_gcc.h" 62 | 63 | /*------------------ ICC Compiler ----------------------*/ 64 | #elif defined ( __ICCARM__ ) 65 | #include 66 | 67 | /*------------------ TI CCS Compiler -------------------*/ 68 | #elif defined ( __TMS470__ ) 69 | #include 70 | 71 | /*------------------ TASKING Compiler ------------------*/ 72 | #elif defined ( __TASKING__ ) 73 | /* 74 | * The CMSIS functions have been implemented as intrinsics in the compiler. 75 | * Please use "carm -?i" to get an up to date list of all intrinsics, 76 | * Including the CMSIS ones. 77 | */ 78 | 79 | /*------------------ COSMIC Compiler -------------------*/ 80 | #elif defined ( __CSMC__ ) 81 | #include 82 | 83 | #endif 84 | 85 | /*@} end of CMSIS_Core_RegAccFunctions */ 86 | 87 | #endif /* __CORE_CMFUNC_H */ 88 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Drivers/CMSIS/Include/core_cmInstr.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file core_cmInstr.h 3 | * @brief CMSIS Cortex-M Core Instruction Access Header File 4 | * @version V4.30 5 | * @date 20. October 2015 6 | ******************************************************************************/ 7 | /* Copyright (c) 2009 - 2015 ARM LIMITED 8 | 9 | All rights reserved. 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | - Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | - Neither the name of ARM nor the names of its contributors may be used 18 | to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | * 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | ---------------------------------------------------------------------------*/ 33 | 34 | 35 | #if defined ( __ICCARM__ ) 36 | #pragma system_include /* treat file as system include file for MISRA check */ 37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 38 | #pragma clang system_header /* treat file as system include file */ 39 | #endif 40 | 41 | #ifndef __CORE_CMINSTR_H 42 | #define __CORE_CMINSTR_H 43 | 44 | 45 | /* ########################## Core Instruction Access ######################### */ 46 | /** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface 47 | Access to dedicated instructions 48 | @{ 49 | */ 50 | 51 | /*------------------ RealView Compiler -----------------*/ 52 | #if defined ( __CC_ARM ) 53 | #include "cmsis_armcc.h" 54 | 55 | /*------------------ ARM Compiler V6 -------------------*/ 56 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 57 | #include "cmsis_armcc_V6.h" 58 | 59 | /*------------------ GNU Compiler ----------------------*/ 60 | #elif defined ( __GNUC__ ) 61 | #include "cmsis_gcc.h" 62 | 63 | /*------------------ ICC Compiler ----------------------*/ 64 | #elif defined ( __ICCARM__ ) 65 | #include 66 | 67 | /*------------------ TI CCS Compiler -------------------*/ 68 | #elif defined ( __TMS470__ ) 69 | #include 70 | 71 | /*------------------ TASKING Compiler ------------------*/ 72 | #elif defined ( __TASKING__ ) 73 | /* 74 | * The CMSIS functions have been implemented as intrinsics in the compiler. 75 | * Please use "carm -?i" to get an up to date list of all intrinsics, 76 | * Including the CMSIS ones. 77 | */ 78 | 79 | /*------------------ COSMIC Compiler -------------------*/ 80 | #elif defined ( __CSMC__ ) 81 | #include 82 | 83 | #endif 84 | 85 | /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ 86 | 87 | #endif /* __CORE_CMINSTR_H */ 88 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Drivers/CMSIS/Include/core_cmSimd.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file core_cmSimd.h 3 | * @brief CMSIS Cortex-M SIMD Header File 4 | * @version V4.30 5 | * @date 20. October 2015 6 | ******************************************************************************/ 7 | /* Copyright (c) 2009 - 2015 ARM LIMITED 8 | 9 | All rights reserved. 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | - Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | - Neither the name of ARM nor the names of its contributors may be used 18 | to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | * 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | ---------------------------------------------------------------------------*/ 33 | 34 | 35 | #if defined ( __ICCARM__ ) 36 | #pragma system_include /* treat file as system include file for MISRA check */ 37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 38 | #pragma clang system_header /* treat file as system include file */ 39 | #endif 40 | 41 | #ifndef __CORE_CMSIMD_H 42 | #define __CORE_CMSIMD_H 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | 49 | /* ################### Compiler specific Intrinsics ########################### */ 50 | /** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics 51 | Access to dedicated SIMD instructions 52 | @{ 53 | */ 54 | 55 | /*------------------ RealView Compiler -----------------*/ 56 | #if defined ( __CC_ARM ) 57 | #include "cmsis_armcc.h" 58 | 59 | /*------------------ ARM Compiler V6 -------------------*/ 60 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 61 | #include "cmsis_armcc_V6.h" 62 | 63 | /*------------------ GNU Compiler ----------------------*/ 64 | #elif defined ( __GNUC__ ) 65 | #include "cmsis_gcc.h" 66 | 67 | /*------------------ ICC Compiler ----------------------*/ 68 | #elif defined ( __ICCARM__ ) 69 | #include 70 | 71 | /*------------------ TI CCS Compiler -------------------*/ 72 | #elif defined ( __TMS470__ ) 73 | #include 74 | 75 | /*------------------ TASKING Compiler ------------------*/ 76 | #elif defined ( __TASKING__ ) 77 | /* 78 | * The CMSIS functions have been implemented as intrinsics in the compiler. 79 | * Please use "carm -?i" to get an up to date list of all intrinsics, 80 | * Including the CMSIS ones. 81 | */ 82 | 83 | /*------------------ COSMIC Compiler -------------------*/ 84 | #elif defined ( __CSMC__ ) 85 | #include 86 | 87 | #endif 88 | 89 | /*@} end of group CMSIS_SIMD_intrinsics */ 90 | 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif /* __CORE_CMSIMD_H */ 97 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Drivers/CMSIS/Lib/libarm_cortexM4lf_math.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/Board/v3/Drivers/CMSIS/Lib/libarm_cortexM4lf_math.a -------------------------------------------------------------------------------- /Firmware/Board/v3/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32f4xx_hal_flash_ramfunc.h 4 | * @author MCD Application Team 5 | * @brief Header file of FLASH RAMFUNC driver. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© COPYRIGHT(c) 2017 STMicroelectronics

10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, 12 | * are permitted provided that the following conditions are met: 13 | * 1. Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | ****************************************************************************** 34 | */ 35 | 36 | /* Define to prevent recursive inclusion -------------------------------------*/ 37 | #ifndef __STM32F4xx_FLASH_RAMFUNC_H 38 | #define __STM32F4xx_FLASH_RAMFUNC_H 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | #if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) || defined(STM32F411xE) || defined(STM32F446xx) || defined(STM32F412Zx) ||\ 44 | defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) 45 | 46 | /* Includes ------------------------------------------------------------------*/ 47 | #include "stm32f4xx_hal_def.h" 48 | 49 | /** @addtogroup STM32F4xx_HAL_Driver 50 | * @{ 51 | */ 52 | 53 | /** @addtogroup FLASH_RAMFUNC 54 | * @{ 55 | */ 56 | 57 | /* Exported types ------------------------------------------------------------*/ 58 | /* Exported macro ------------------------------------------------------------*/ 59 | /* Exported functions --------------------------------------------------------*/ 60 | /** @addtogroup FLASH_RAMFUNC_Exported_Functions 61 | * @{ 62 | */ 63 | 64 | /** @addtogroup FLASH_RAMFUNC_Exported_Functions_Group1 65 | * @{ 66 | */ 67 | __RAM_FUNC HAL_FLASHEx_StopFlashInterfaceClk(void); 68 | __RAM_FUNC HAL_FLASHEx_StartFlashInterfaceClk(void); 69 | __RAM_FUNC HAL_FLASHEx_EnableFlashSleepMode(void); 70 | __RAM_FUNC HAL_FLASHEx_DisableFlashSleepMode(void); 71 | /** 72 | * @} 73 | */ 74 | 75 | /** 76 | * @} 77 | */ 78 | 79 | /** 80 | * @} 81 | */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | #endif /* STM32F410xx || STM32F411xE || STM32F446xx || STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx */ 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | 93 | #endif /* __STM32F4xx_FLASH_RAMFUNC_H */ 94 | 95 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 96 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/adc.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : ADC.h 4 | * Description : This file provides code for the configuration 5 | * of the ADC instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __adc_H 51 | #define __adc_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern ADC_HandleTypeDef hadc1; 65 | extern ADC_HandleTypeDef hadc2; 66 | extern ADC_HandleTypeDef hadc3; 67 | 68 | /* USER CODE BEGIN Private defines */ 69 | 70 | /* USER CODE END Private defines */ 71 | 72 | extern void _Error_Handler(char *, int); 73 | 74 | void MX_ADC1_Init(void); 75 | void MX_ADC2_Init(void); 76 | void MX_ADC3_Init(void); 77 | 78 | /* USER CODE BEGIN Prototypes */ 79 | 80 | float read_ADC_volts(ADC_HandleTypeDef* hadc, uint8_t injected_rank); 81 | 82 | /* USER CODE END Prototypes */ 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | #endif /*__ adc_H */ 88 | 89 | /** 90 | * @} 91 | */ 92 | 93 | /** 94 | * @} 95 | */ 96 | 97 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 98 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/can.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : CAN.h 4 | * Description : This file provides code for the configuration 5 | * of the CAN instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __can_H 51 | #define __can_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern CAN_HandleTypeDef hcan1; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_CAN1_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ can_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/dma.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : dma.h 4 | * Description : This file contains all the function prototypes for 5 | * the dma.c file 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __dma_H 51 | #define __dma_H 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /* Includes ------------------------------------------------------------------*/ 58 | #include "stm32f4xx_hal.h" 59 | #include "main.h" 60 | 61 | /* DMA memory to memory transfer handles -------------------------------------*/ 62 | extern void _Error_Handler(char*, int); 63 | 64 | /* USER CODE BEGIN Includes */ 65 | 66 | /* USER CODE END Includes */ 67 | 68 | /* USER CODE BEGIN Private defines */ 69 | 70 | /* USER CODE END Private defines */ 71 | 72 | void MX_DMA_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif /* __dma_H */ 83 | 84 | /** 85 | * @} 86 | */ 87 | 88 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 89 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/freertos_vars.h: -------------------------------------------------------------------------------- 1 | /* Define to prevent recursive inclusion -------------------------------------*/ 2 | #ifndef __FREERTOS_H 3 | #define __FREERTOS_H 4 | 5 | // List of semaphores 6 | extern osSemaphoreId sem_usb_irq; 7 | extern osSemaphoreId sem_uart_dma; 8 | extern osSemaphoreId sem_usb_rx; 9 | extern osSemaphoreId sem_usb_tx; 10 | 11 | extern osThreadId defaultTaskHandle; 12 | extern osThreadId usb_irq_thread; 13 | 14 | #endif /* __FREERTOS_H */ -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/i2c.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : I2C.h 4 | * Description : This file provides code for the configuration 5 | * of the I2C instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __i2c_H 51 | #define __i2c_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern I2C_HandleTypeDef hi2c1; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_I2C1_Init(uint8_t addr); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ i2c_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/prev_board_ver/main_V3_2.h: -------------------------------------------------------------------------------- 1 | 2 | /* Private define ------------------------------------------------------------*/ 3 | #define TIM_1_8_CLOCK_HZ 168000000 4 | #define TIM_1_8_PERIOD_CLOCKS 10192 5 | #define TIM_1_8_DEADTIME_CLOCKS 20 6 | #define TIM_APB1_CLOCK_HZ 84000000 7 | #define TIM_APB1_PERIOD_CLOCKS 4096 8 | #define TIM_APB1_DEADTIME_CLOCKS 40 9 | #define configAPPLICATION_ALLOCATED_HEAP 1 10 | 11 | #define M0_nCS_Pin GPIO_PIN_13 12 | #define M0_nCS_GPIO_Port GPIOC 13 | #define M1_nCS_Pin GPIO_PIN_14 14 | #define M1_nCS_GPIO_Port GPIOC 15 | #define M1_DC_CAL_Pin GPIO_PIN_15 16 | #define M1_DC_CAL_GPIO_Port GPIOC 17 | #define M0_IB_Pin GPIO_PIN_0 18 | #define M0_IB_GPIO_Port GPIOC 19 | #define M0_IC_Pin GPIO_PIN_1 20 | #define M0_IC_GPIO_Port GPIOC 21 | #define M1_IC_Pin GPIO_PIN_2 22 | #define M1_IC_GPIO_Port GPIOC 23 | #define M1_IB_Pin GPIO_PIN_3 24 | #define M1_IB_GPIO_Port GPIOC 25 | #define VBUS_S_Pin GPIO_PIN_0 26 | #define VBUS_S_GPIO_Port GPIOA 27 | #define M1_TEMP_Pin GPIO_PIN_1 28 | #define M1_TEMP_GPIO_Port GPIOA 29 | #define AUX_I_Pin GPIO_PIN_2 30 | #define AUX_I_GPIO_Port GPIOA 31 | #define GPIO_4_Pin GPIO_PIN_3 32 | #define GPIO_4_GPIO_Port GPIOA 33 | #define GPIO_3_Pin GPIO_PIN_4 34 | #define GPIO_3_GPIO_Port GPIOA 35 | #define GPIO_3_EXTI_IRQn EXTI4_IRQn 36 | #define GPIO_2_Pin GPIO_PIN_5 37 | #define GPIO_2_GPIO_Port GPIOA 38 | #define AUX_V_Pin GPIO_PIN_6 39 | #define AUX_V_GPIO_Port GPIOA 40 | #define M1_AL_Pin GPIO_PIN_7 41 | #define M1_AL_GPIO_Port GPIOA 42 | #define AUX_TEMP_Pin GPIO_PIN_4 43 | #define AUX_TEMP_GPIO_Port GPIOC 44 | #define M0_TEMP_Pin GPIO_PIN_5 45 | #define M0_TEMP_GPIO_Port GPIOC 46 | #define M1_BL_Pin GPIO_PIN_0 47 | #define M1_BL_GPIO_Port GPIOB 48 | #define M1_CL_Pin GPIO_PIN_1 49 | #define M1_CL_GPIO_Port GPIOB 50 | #define GPIO_1_Pin GPIO_PIN_2 51 | #define GPIO_1_GPIO_Port GPIOB 52 | #define GPIO_1_EXTI_IRQn EXTI2_IRQn 53 | #define AUX_L_Pin GPIO_PIN_10 54 | #define AUX_L_GPIO_Port GPIOB 55 | #define AUX_H_Pin GPIO_PIN_11 56 | #define AUX_H_GPIO_Port GPIOB 57 | #define EN_GATE_Pin GPIO_PIN_12 58 | #define EN_GATE_GPIO_Port GPIOB 59 | #define M0_AL_Pin GPIO_PIN_13 60 | #define M0_AL_GPIO_Port GPIOB 61 | #define M0_BL_Pin GPIO_PIN_14 62 | #define M0_BL_GPIO_Port GPIOB 63 | #define M0_CL_Pin GPIO_PIN_15 64 | #define M0_CL_GPIO_Port GPIOB 65 | #define M1_AH_Pin GPIO_PIN_6 66 | #define M1_AH_GPIO_Port GPIOC 67 | #define M1_BH_Pin GPIO_PIN_7 68 | #define M1_BH_GPIO_Port GPIOC 69 | #define M1_CH_Pin GPIO_PIN_8 70 | #define M1_CH_GPIO_Port GPIOC 71 | #define M0_DC_CAL_Pin GPIO_PIN_9 72 | #define M0_DC_CAL_GPIO_Port GPIOC 73 | #define M0_AH_Pin GPIO_PIN_8 74 | #define M0_AH_GPIO_Port GPIOA 75 | #define M0_BH_Pin GPIO_PIN_9 76 | #define M0_BH_GPIO_Port GPIOA 77 | #define M0_CH_Pin GPIO_PIN_10 78 | #define M0_CH_GPIO_Port GPIOA 79 | #define M0_ENC_Z_Pin GPIO_PIN_15 80 | #define M0_ENC_Z_GPIO_Port GPIOA 81 | #define nFAULT_Pin GPIO_PIN_2 82 | #define nFAULT_GPIO_Port GPIOD 83 | #define M1_ENC_Z_Pin GPIO_PIN_3 84 | #define M1_ENC_Z_GPIO_Port GPIOB 85 | #define M0_ENC_A_Pin GPIO_PIN_4 86 | #define M0_ENC_A_GPIO_Port GPIOB 87 | #define M0_ENC_B_Pin GPIO_PIN_5 88 | #define M0_ENC_B_GPIO_Port GPIOB 89 | #define M1_ENC_A_Pin GPIO_PIN_6 90 | #define M1_ENC_A_GPIO_Port GPIOB 91 | #define M1_ENC_B_Pin GPIO_PIN_7 92 | #define M1_ENC_B_GPIO_Port GPIOB 93 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/prev_board_ver/main_V3_4.h: -------------------------------------------------------------------------------- 1 | 2 | /* Private define ------------------------------------------------------------*/ 3 | #define TIM_1_8_CLOCK_HZ 168000000 4 | #define TIM_1_8_PERIOD_CLOCKS 10192 5 | #define TIM_1_8_DEADTIME_CLOCKS 20 6 | #define TIM_APB1_CLOCK_HZ 84000000 7 | #define TIM_APB1_PERIOD_CLOCKS 4096 8 | #define TIM_APB1_DEADTIME_CLOCKS 40 9 | #define configAPPLICATION_ALLOCATED_HEAP 1 10 | 11 | #define M0_nCS_Pin GPIO_PIN_13 12 | #define M0_nCS_GPIO_Port GPIOC 13 | #define M1_nCS_Pin GPIO_PIN_14 14 | #define M1_nCS_GPIO_Port GPIOC 15 | #define M1_DC_CAL_Pin GPIO_PIN_15 16 | #define M1_DC_CAL_GPIO_Port GPIOC 17 | #define M0_IB_Pin GPIO_PIN_0 18 | #define M0_IB_GPIO_Port GPIOC 19 | #define M0_IC_Pin GPIO_PIN_1 20 | #define M0_IC_GPIO_Port GPIOC 21 | #define M1_IC_Pin GPIO_PIN_2 22 | #define M1_IC_GPIO_Port GPIOC 23 | #define M1_IB_Pin GPIO_PIN_3 24 | #define M1_IB_GPIO_Port GPIOC 25 | #define GPIO_1_Pin GPIO_PIN_0 26 | #define GPIO_1_GPIO_Port GPIOA 27 | #define GPIO_2_Pin GPIO_PIN_1 28 | #define GPIO_2_GPIO_Port GPIOA 29 | #define GPIO_3_Pin GPIO_PIN_2 30 | #define GPIO_3_GPIO_Port GPIOA 31 | #define GPIO_3_EXTI_IRQn EXTI2_IRQn 32 | #define GPIO_4_Pin GPIO_PIN_3 33 | #define GPIO_4_GPIO_Port GPIOA 34 | #define M1_TEMP_Pin GPIO_PIN_4 35 | #define M1_TEMP_GPIO_Port GPIOA 36 | #define AUX_I_Pin GPIO_PIN_5 37 | #define AUX_I_GPIO_Port GPIOA 38 | #define VBUS_S_Pin GPIO_PIN_6 39 | #define VBUS_S_GPIO_Port GPIOA 40 | #define M1_AL_Pin GPIO_PIN_7 41 | #define M1_AL_GPIO_Port GPIOA 42 | #define AUX_TEMP_Pin GPIO_PIN_4 43 | #define AUX_TEMP_GPIO_Port GPIOC 44 | #define M0_TEMP_Pin GPIO_PIN_5 45 | #define M0_TEMP_GPIO_Port GPIOC 46 | #define M1_BL_Pin GPIO_PIN_0 47 | #define M1_BL_GPIO_Port GPIOB 48 | #define M1_CL_Pin GPIO_PIN_1 49 | #define M1_CL_GPIO_Port GPIOB 50 | #define GPIO_5_Pin GPIO_PIN_2 51 | #define GPIO_5_GPIO_Port GPIOB 52 | #define AUX_L_Pin GPIO_PIN_10 53 | #define AUX_L_GPIO_Port GPIOB 54 | #define AUX_H_Pin GPIO_PIN_11 55 | #define AUX_H_GPIO_Port GPIOB 56 | #define EN_GATE_Pin GPIO_PIN_12 57 | #define EN_GATE_GPIO_Port GPIOB 58 | #define M0_AL_Pin GPIO_PIN_13 59 | #define M0_AL_GPIO_Port GPIOB 60 | #define M0_BL_Pin GPIO_PIN_14 61 | #define M0_BL_GPIO_Port GPIOB 62 | #define M0_CL_Pin GPIO_PIN_15 63 | #define M0_CL_GPIO_Port GPIOB 64 | #define M1_AH_Pin GPIO_PIN_6 65 | #define M1_AH_GPIO_Port GPIOC 66 | #define M1_BH_Pin GPIO_PIN_7 67 | #define M1_BH_GPIO_Port GPIOC 68 | #define M1_CH_Pin GPIO_PIN_8 69 | #define M1_CH_GPIO_Port GPIOC 70 | #define M0_DC_CAL_Pin GPIO_PIN_9 71 | #define M0_DC_CAL_GPIO_Port GPIOC 72 | #define M0_AH_Pin GPIO_PIN_8 73 | #define M0_AH_GPIO_Port GPIOA 74 | #define M0_BH_Pin GPIO_PIN_9 75 | #define M0_BH_GPIO_Port GPIOA 76 | #define M0_CH_Pin GPIO_PIN_10 77 | #define M0_CH_GPIO_Port GPIOA 78 | #define M0_ENC_Z_Pin GPIO_PIN_15 79 | #define M0_ENC_Z_GPIO_Port GPIOA 80 | #define nFAULT_Pin GPIO_PIN_2 81 | #define nFAULT_GPIO_Port GPIOD 82 | #define M1_ENC_Z_Pin GPIO_PIN_3 83 | #define M1_ENC_Z_GPIO_Port GPIOB 84 | #define M0_ENC_A_Pin GPIO_PIN_4 85 | #define M0_ENC_A_GPIO_Port GPIOB 86 | #define M0_ENC_B_Pin GPIO_PIN_5 87 | #define M0_ENC_B_GPIO_Port GPIOB 88 | #define M1_ENC_A_Pin GPIO_PIN_6 89 | #define M1_ENC_A_GPIO_Port GPIOB 90 | #define M1_ENC_B_Pin GPIO_PIN_7 91 | #define M1_ENC_B_GPIO_Port GPIOB 92 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/spi.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : SPI.h 4 | * Description : This file provides code for the configuration 5 | * of the SPI instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __spi_H 51 | #define __spi_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern SPI_HandleTypeDef hspi3; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_SPI3_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ spi_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/stm32f4xx_it.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32f4xx_it.h 4 | * @brief This file contains the headers of the interrupt handlers. 5 | ****************************************************************************** 6 | * 7 | * COPYRIGHT(c) 2018 STMicroelectronics 8 | * 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | ****************************************************************************** 32 | */ 33 | 34 | /* Define to prevent recursive inclusion -------------------------------------*/ 35 | #ifndef __STM32F4xx_IT_H 36 | #define __STM32F4xx_IT_H 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /* Includes ------------------------------------------------------------------*/ 43 | #include "stm32f4xx_hal.h" 44 | #include "main.h" 45 | /* Exported types ------------------------------------------------------------*/ 46 | /* Exported constants --------------------------------------------------------*/ 47 | /* Exported macro ------------------------------------------------------------*/ 48 | /* Exported functions ------------------------------------------------------- */ 49 | 50 | void NMI_Handler(void); 51 | void HardFault_Handler(void); 52 | void MemManage_Handler(void); 53 | void BusFault_Handler(void); 54 | void UsageFault_Handler(void); 55 | void DebugMon_Handler(void); 56 | void SysTick_Handler(void); 57 | void DMA1_Stream2_IRQHandler(void); 58 | void DMA1_Stream4_IRQHandler(void); 59 | void ADC_IRQHandler(void); 60 | void CAN1_TX_IRQHandler(void); 61 | void CAN1_RX0_IRQHandler(void); 62 | void CAN1_RX1_IRQHandler(void); 63 | void CAN1_SCE_IRQHandler(void); 64 | void TIM8_TRG_COM_TIM14_IRQHandler(void); 65 | void UART4_IRQHandler(void); 66 | void OTG_FS_IRQHandler(void); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif /* __STM32F4xx_IT_H */ 73 | 74 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 75 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Inc/usart.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : USART.h 4 | * Description : This file provides code for the configuration 5 | * of the USART instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __usart_H 51 | #define __usart_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern UART_HandleTypeDef huart4; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_UART4_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ usart_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # This file is partially autogenerated. If you let CubeMX generate the code, 3 | # it will edit this file to update the source and include list. This editing 4 | # is not very robust, so be careful with changing the format of this file. 5 | 6 | ###################################### 7 | # source 8 | ###################################### 9 | C_SOURCES = \ 10 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c \ 11 | Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \ 12 | Src/stm32f4xx_hal_timebase_TIM.c \ 13 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_can.c \ 14 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c \ 15 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c \ 16 | Src/tim.c \ 17 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c \ 18 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c \ 19 | Src/dma.c \ 20 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c \ 21 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c \ 22 | Src/freertos.c \ 23 | Src/main.c \ 24 | Src/usbd_conf.c \ 25 | Src/spi.c \ 26 | Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \ 27 | Src/usart.c \ 28 | Middlewares/Third_Party/FreeRTOS/Source/croutine.c \ 29 | Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \ 30 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c \ 31 | Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \ 32 | Src/usbd_cdc_if.c \ 33 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c \ 34 | Src/adc.c \ 35 | Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \ 36 | Middlewares/Third_Party/FreeRTOS/Source/list.c \ 37 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c \ 38 | Src/stm32f4xx_hal_msp.c \ 39 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c \ 40 | Src/usbd_desc.c \ 41 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c \ 42 | Src/stm32f4xx_it.c \ 43 | Src/usb_device.c \ 44 | Src/can.c \ 45 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c \ 46 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c \ 47 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c \ 48 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c \ 49 | Middlewares/Third_Party/FreeRTOS/Source/queue.c \ 50 | Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c \ 51 | Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \ 52 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c \ 53 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c \ 54 | Src/system_stm32f4xx.c \ 55 | Src/gpio.c \ 56 | Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ 57 | Middlewares/Third_Party/FreeRTOS/Source/timers.c \ 58 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c \ 59 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c \ 60 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c \ 61 | Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ 62 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c \ 63 | Src/i2c.c \ 64 | Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c 65 | 66 | ASM_SOURCES = \ 67 | startup_stm32f405xx.s 68 | 69 | ####################################### 70 | # Includes 71 | ####################################### 72 | AS_INCLUDES = 73 | 74 | C_INCLUDES = \ 75 | -IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \ 76 | -IMiddlewares/Third_Party/FreeRTOS/Source/include \ 77 | -IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS \ 78 | -IMiddlewares/ST/STM32_USB_Device_Library/Core/Inc \ 79 | -IMiddlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \ 80 | -IDrivers/STM32F4xx_HAL_Driver/Inc \ 81 | -IDrivers/STM32F4xx_HAL_Driver/Inc/Legacy \ 82 | -IDrivers/CMSIS/Device/ST/STM32F4xx/Include \ 83 | -IDrivers/CMSIS/Include \ 84 | -IInc 85 | 86 | # CubeMX insists on this line 87 | Inc 88 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file usbd_req.h 4 | * @author MCD Application Team 5 | * @version V2.4.2 6 | * @date 11-December-2015 7 | * @brief Header file for the usbd_req.c file 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT 2015 STMicroelectronics

12 | * 13 | * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); 14 | * You may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at: 16 | * 17 | * http://www.st.com/software_license_agreement_liberty_v2 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | * 25 | ****************************************************************************** 26 | */ 27 | 28 | /* Define to prevent recursive inclusion -------------------------------------*/ 29 | #ifndef __USB_REQUEST_H 30 | #define __USB_REQUEST_H 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /* Includes ------------------------------------------------------------------*/ 37 | #include "usbd_def.h" 38 | 39 | 40 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 41 | * @{ 42 | */ 43 | 44 | /** @defgroup USBD_REQ 45 | * @brief header file for the usbd_req.c file 46 | * @{ 47 | */ 48 | 49 | /** @defgroup USBD_REQ_Exported_Defines 50 | * @{ 51 | */ 52 | /** 53 | * @} 54 | */ 55 | 56 | 57 | /** @defgroup USBD_REQ_Exported_Types 58 | * @{ 59 | */ 60 | /** 61 | * @} 62 | */ 63 | 64 | 65 | 66 | /** @defgroup USBD_REQ_Exported_Macros 67 | * @{ 68 | */ 69 | /** 70 | * @} 71 | */ 72 | 73 | /** @defgroup USBD_REQ_Exported_Variables 74 | * @{ 75 | */ 76 | /** 77 | * @} 78 | */ 79 | 80 | /** @defgroup USBD_REQ_Exported_FunctionsPrototype 81 | * @{ 82 | */ 83 | 84 | USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 85 | USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 86 | USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 87 | 88 | 89 | void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 90 | 91 | void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); 92 | 93 | void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len); 94 | /** 95 | * @} 96 | */ 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif /* __USB_REQUEST_H */ 103 | 104 | /** 105 | * @} 106 | */ 107 | 108 | /** 109 | * @} 110 | */ 111 | 112 | 113 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 114 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file usbd_ioreq.h 4 | * @author MCD Application Team 5 | * @version V2.4.2 6 | * @date 11-December-2015 7 | * @brief Header file for the usbd_ioreq.c file 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT 2015 STMicroelectronics

12 | * 13 | * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); 14 | * You may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at: 16 | * 17 | * http://www.st.com/software_license_agreement_liberty_v2 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | * 25 | ****************************************************************************** 26 | */ 27 | 28 | /* Define to prevent recursive inclusion -------------------------------------*/ 29 | #ifndef __USBD_IOREQ_H 30 | #define __USBD_IOREQ_H 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /* Includes ------------------------------------------------------------------*/ 37 | #include "usbd_def.h" 38 | #include "usbd_core.h" 39 | 40 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 41 | * @{ 42 | */ 43 | 44 | /** @defgroup USBD_IOREQ 45 | * @brief header file for the usbd_ioreq.c file 46 | * @{ 47 | */ 48 | 49 | /** @defgroup USBD_IOREQ_Exported_Defines 50 | * @{ 51 | */ 52 | /** 53 | * @} 54 | */ 55 | 56 | 57 | /** @defgroup USBD_IOREQ_Exported_Types 58 | * @{ 59 | */ 60 | 61 | 62 | /** 63 | * @} 64 | */ 65 | 66 | 67 | 68 | /** @defgroup USBD_IOREQ_Exported_Macros 69 | * @{ 70 | */ 71 | 72 | /** 73 | * @} 74 | */ 75 | 76 | /** @defgroup USBD_IOREQ_Exported_Variables 77 | * @{ 78 | */ 79 | 80 | /** 81 | * @} 82 | */ 83 | 84 | /** @defgroup USBD_IOREQ_Exported_FunctionsPrototype 85 | * @{ 86 | */ 87 | 88 | USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, 89 | uint8_t *buf, 90 | uint16_t len); 91 | 92 | USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, 93 | uint8_t *pbuf, 94 | uint16_t len); 95 | 96 | USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, 97 | uint8_t *pbuf, 98 | uint16_t len); 99 | 100 | USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, 101 | uint8_t *pbuf, 102 | uint16_t len); 103 | 104 | USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev); 105 | 106 | USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev); 107 | 108 | uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , 109 | uint8_t epnum); 110 | 111 | /** 112 | * @} 113 | */ 114 | 115 | #ifdef __cplusplus 116 | } 117 | #endif 118 | 119 | #endif /* __USBD_IOREQ_H */ 120 | 121 | /** 122 | * @} 123 | */ 124 | 125 | /** 126 | * @} 127 | */ 128 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 129 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c -------------------------------------------------------------------------------- /Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h -------------------------------------------------------------------------------- /Firmware/Board/v3/Src/prev_board_ver/gpio_V3_2.c: -------------------------------------------------------------------------------- 1 | /** Configure pins as 2 | * Analog 3 | * Input 4 | * Output 5 | * EVENT_OUT 6 | * EXTI 7 | */ 8 | void MX_GPIO_Init(void) 9 | { 10 | 11 | GPIO_InitTypeDef GPIO_InitStruct; 12 | 13 | /* GPIO Ports Clock Enable */ 14 | __HAL_RCC_GPIOC_CLK_ENABLE(); 15 | __HAL_RCC_GPIOH_CLK_ENABLE(); 16 | __HAL_RCC_GPIOA_CLK_ENABLE(); 17 | __HAL_RCC_GPIOB_CLK_ENABLE(); 18 | __HAL_RCC_GPIOD_CLK_ENABLE(); 19 | 20 | /*Configure GPIO pin Output Level */ 21 | HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET); 22 | 23 | /*Configure GPIO pin Output Level */ 24 | HAL_GPIO_WritePin(GPIOC, M1_DC_CAL_Pin|M0_DC_CAL_Pin, GPIO_PIN_RESET); 25 | 26 | /*Configure GPIO pin Output Level */ 27 | HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET); 28 | 29 | /*Configure GPIO pins : PCPin PCPin PCPin PCPin */ 30 | GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin|M1_DC_CAL_Pin|M0_DC_CAL_Pin; 31 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 32 | GPIO_InitStruct.Pull = GPIO_NOPULL; 33 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 34 | HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 35 | 36 | /*Configure GPIO pins : PAPin PAPin */ 37 | GPIO_InitStruct.Pin = GPIO_4_Pin|GPIO_2_Pin; 38 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 39 | GPIO_InitStruct.Pull = GPIO_PULLDOWN; 40 | HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 41 | 42 | /*Configure GPIO pin : PtPin */ 43 | GPIO_InitStruct.Pin = GPIO_3_Pin; 44 | GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; 45 | GPIO_InitStruct.Pull = GPIO_PULLDOWN; 46 | HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct); 47 | 48 | /*Configure GPIO pin : PtPin */ 49 | GPIO_InitStruct.Pin = GPIO_1_Pin; 50 | GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; 51 | GPIO_InitStruct.Pull = GPIO_PULLDOWN; 52 | HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct); 53 | 54 | /*Configure GPIO pin : PtPin */ 55 | GPIO_InitStruct.Pin = EN_GATE_Pin; 56 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 57 | GPIO_InitStruct.Pull = GPIO_NOPULL; 58 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 59 | HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct); 60 | 61 | /*Configure GPIO pin : PtPin */ 62 | GPIO_InitStruct.Pin = M0_ENC_Z_Pin; 63 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 64 | GPIO_InitStruct.Pull = GPIO_NOPULL; 65 | HAL_GPIO_Init(M0_ENC_Z_GPIO_Port, &GPIO_InitStruct); 66 | 67 | /*Configure GPIO pin : PtPin */ 68 | GPIO_InitStruct.Pin = nFAULT_Pin; 69 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 70 | GPIO_InitStruct.Pull = GPIO_PULLUP; 71 | HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct); 72 | 73 | /*Configure GPIO pin : PtPin */ 74 | GPIO_InitStruct.Pin = M1_ENC_Z_Pin; 75 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 76 | GPIO_InitStruct.Pull = GPIO_NOPULL; 77 | HAL_GPIO_Init(M1_ENC_Z_GPIO_Port, &GPIO_InitStruct); 78 | 79 | /* EXTI interrupt init*/ 80 | HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); 81 | HAL_NVIC_EnableIRQ(EXTI2_IRQn); 82 | 83 | HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0); 84 | HAL_NVIC_EnableIRQ(EXTI4_IRQn); 85 | 86 | } -------------------------------------------------------------------------------- /Firmware/Board/v3/Src/prev_board_ver/gpio_V3_4.c: -------------------------------------------------------------------------------- 1 | /** Configure pins as 2 | * Analog 3 | * Input 4 | * Output 5 | * EVENT_OUT 6 | * EXTI 7 | */ 8 | void MX_GPIO_Init(void) 9 | { 10 | 11 | GPIO_InitTypeDef GPIO_InitStruct; 12 | 13 | /* GPIO Ports Clock Enable */ 14 | __HAL_RCC_GPIOC_CLK_ENABLE(); 15 | __HAL_RCC_GPIOH_CLK_ENABLE(); 16 | __HAL_RCC_GPIOA_CLK_ENABLE(); 17 | __HAL_RCC_GPIOB_CLK_ENABLE(); 18 | __HAL_RCC_GPIOD_CLK_ENABLE(); 19 | 20 | /*Configure GPIO pin Output Level */ 21 | HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET); 22 | 23 | /*Configure GPIO pin Output Level */ 24 | HAL_GPIO_WritePin(GPIOC, M1_DC_CAL_Pin|M0_DC_CAL_Pin, GPIO_PIN_RESET); 25 | 26 | /*Configure GPIO pin Output Level */ 27 | HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET); 28 | 29 | /*Configure GPIO pins : PCPin PCPin PCPin PCPin */ 30 | GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin|M1_DC_CAL_Pin|M0_DC_CAL_Pin; 31 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 32 | GPIO_InitStruct.Pull = GPIO_NOPULL; 33 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 34 | HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 35 | 36 | /*Configure GPIO pin : PtPin */ 37 | GPIO_InitStruct.Pin = GPIO_3_Pin; 38 | GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; 39 | GPIO_InitStruct.Pull = GPIO_PULLDOWN; 40 | HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct); 41 | 42 | /*Configure GPIO pins : PAPin PAPin */ 43 | GPIO_InitStruct.Pin = GPIO_4_Pin|M0_ENC_Z_Pin; 44 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 45 | GPIO_InitStruct.Pull = GPIO_NOPULL; 46 | HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 47 | 48 | /*Configure GPIO pins : PBPin PBPin */ 49 | GPIO_InitStruct.Pin = GPIO_5_Pin|M1_ENC_Z_Pin; 50 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 51 | GPIO_InitStruct.Pull = GPIO_NOPULL; 52 | HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 53 | 54 | /*Configure GPIO pin : PtPin */ 55 | GPIO_InitStruct.Pin = EN_GATE_Pin; 56 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 57 | GPIO_InitStruct.Pull = GPIO_NOPULL; 58 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 59 | HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct); 60 | 61 | /*Configure GPIO pin : PtPin */ 62 | GPIO_InitStruct.Pin = nFAULT_Pin; 63 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 64 | GPIO_InitStruct.Pull = GPIO_PULLUP; 65 | HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct); 66 | 67 | /* EXTI interrupt init*/ 68 | HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); 69 | HAL_NVIC_EnableIRQ(EXTI2_IRQn); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Firmware/Board/v3/Src/syscalls.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file : syscalls.c 4 | * @brief : This file implements printf functionality 5 | ****************************************************************************** 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | //int _read(int file, char *data, int len) {} 16 | //int _close(int file) {} 17 | //int _lseek(int file, int ptr, int dir) {} 18 | //int _fstat(int file, struct stat *st) {} 19 | //int _isatty(int file) {} 20 | 21 | extern char _end; // provided by the linker script: it's end of statically allocated section, which is where the heap starts. 22 | extern char _heap_end_max; // provided by the linker script 23 | void* _end_ptr = &_end; 24 | void* _heap_end_max_ptr = &_heap_end_max; 25 | void* heap_end_ptr = 0; 26 | 27 | /* @brief Increments the program break (aka heap end) 28 | * 29 | * This is called internally by malloc once it runs out 30 | * of heap space. Malloc might expect a contiguous heap, 31 | * so we don't call the FreeRTOS pvPortMalloc here. 32 | * If this function returns -1, malloc will return NULL. 33 | * Note that if this function returns NULL, malloc does not 34 | * consider this as an error and will return the pointer 0x8. 35 | * 36 | * You should still be careful with using malloc though, 37 | * as it does not guarantee thread safety. 38 | * 39 | * @return A pointer to the newly allocated block on success 40 | * or -1 otherwise. 41 | */ 42 | intptr_t _sbrk(size_t size) { 43 | intptr_t ptr; 44 | vTaskSuspendAll(); 45 | { 46 | if (!heap_end_ptr) 47 | heap_end_ptr = _end_ptr; 48 | if (heap_end_ptr + size > _heap_end_max_ptr) { 49 | ptr = -1; 50 | } else { 51 | ptr = (intptr_t)heap_end_ptr; 52 | heap_end_ptr += size; 53 | } 54 | } 55 | (void)xTaskResumeAll(); 56 | return ptr; 57 | } 58 | 59 | // _write is defined in communication.cpp 60 | 61 | 62 | -------------------------------------------------------------------------------- /Firmware/FreeRTOS-openocd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer 3 | * present in the kernel, so it has to be supplied by other means for 4 | * OpenOCD's threads awareness. 5 | * 6 | * Add this file to your project, and, if you're using --gc-sections, 7 | * ``--undefined=uxTopUsedPriority'' (or 8 | * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final 9 | * linking) to your LDFLAGS; same with all the other symbols you need. 10 | */ 11 | 12 | #include "FreeRTOS.h" 13 | 14 | #ifdef __GNUC__ 15 | #define USED __attribute__((used)) 16 | #else 17 | #define USED 18 | #endif 19 | 20 | const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; 21 | -------------------------------------------------------------------------------- /Firmware/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Oskar Weigl (madcowswe) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Firmware/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # This is only a stub for various commands. 3 | # Tup is used for the actual compilation. 4 | 5 | BUILD_DIR = build 6 | FIRMWARE = $(BUILD_DIR)/ODriveFirmware.elf 7 | FIRMWARE_HEX = $(BUILD_DIR)/ODriveFirmware.hex 8 | OPENOCD := openocd -f interface/stlink-v2.cfg \ 9 | $(if $(value PROGRAMMER),-c 'hla_serial $(PROGRAMMER)',) \ 10 | -f target/stm32f4x.cfg 11 | 12 | 13 | all: 14 | @tup --quiet --no-environ-check 15 | 16 | flash: all 17 | $(OPENOCD) -c init \ 18 | -c 'reset halt' \ 19 | -c 'flash write_image erase $(FIRMWARE)' \ 20 | -c 'reset run' \ 21 | -c exit 22 | 23 | gdb: all 24 | arm-none-eabi-gdb $(FIRMWARE) -x openocd.gdbinit 25 | 26 | dfu: all 27 | python ../tools/odrivetool $(if $(value SERIAL_NUMBER),--serial-number $(SERIAL_NUMBER),) dfu $(FIRMWARE_HEX) 28 | 29 | bmp: all 30 | arm-none-eabi-gdb --ex 'target extended-remote /dev/stlink' \ 31 | --ex 'monitor swdp_scan' \ 32 | --ex 'attach 1' \ 33 | --ex 'load' $(FIRMWARE) 34 | 35 | # Erase entire STM32 36 | erase: 37 | $(OPENOCD) -c init -c reset\ halt -c flash\ erase_address\ 0x8000000\ 0x100000 -c reset\ run -c exit 38 | 39 | # Erase all configuration from the ODrive 40 | erase_config: 41 | $(OPENOCD) -c init -c reset\ halt -c flash\ erase_address\ 0x80C0000\ 0x40000 -c reset\ init -c reset\ run -c exit 42 | 43 | # The one-time programmable memory stores the board version 44 | # has the following format: 45 | # - OTP format version (0xFE: version 1) 46 | # - vendor ID (01: ODrive Robotics - do not use this on custom incompatible hardware!) 47 | # - product ID (01: ODrive) 48 | # - hardware major version 49 | # - hardware minor version 50 | # - hardware variant (equal to the board nominal voltage) 51 | # Bits in the OTP can only ever be set to 0 but never back to 1. 52 | # Therefore do not try to run this command on the same board 53 | # twice with different data. 54 | # 55 | # This OpenOCD command is intended for a STM32F405 and does the following: 56 | # FLASH_KEYR = 0x45670123; // unlock FLASH_CR 57 | # FLASH_KEYR = 0xCDEF89AB; // unlock FLASH_CR 58 | # FLASH_CR = (1 << FLASH_CR_PG); // unlock flash memory 59 | # [write OTP] 60 | write_otp: 61 | ifeq ($(OTP_CONFIRM),TRUE) 62 | # Data: 63 | $(OPENOCD) \ 64 | -c init \ 65 | -c 'reset halt' \ 66 | -c 'mww 0x40023C04 0x45670123' \ 67 | -c 'mww 0x40023C04 0xCDEF89AB' \ 68 | -c 'mww 0x40023C10 0x00000001' -c 'sleep 10' \ 69 | -c 'mwb 0x1fff7800 0xFE' -c 'sleep 10' \ 70 | -c 'mwb 0x1fff7801 0x01' -c 'sleep 10' \ 71 | -c 'mwb 0x1fff7802 0x01' -c 'sleep 10' \ 72 | -c 'mwb 0x1fff7803 3' -c 'sleep 10' \ 73 | -c 'mwb 0x1fff7804 5' -c 'sleep 10' \ 74 | -c 'mwb 0x1fff7805 48' -c 'sleep 10' \ 75 | -c 'reset run' \ 76 | -c exit 77 | @echo "OK" 78 | else 79 | @echo "The one-time programmable memory can only be" 80 | @echo "written ONCE on every board (what a surprise)." 81 | @echo "If you're on an ODrive v3.5 or later we already did this for you." 82 | @echo "Otherwise, if you're mentally ready for this irreversible action," 83 | @echo "take the following steps:" 84 | @echo " 1. open the Makefile and look at the write_otp target" 85 | @echo " 2. understand the structure of the OTP" 86 | @echo " 3. edit the bytes that are written to match your board version" 87 | @echo "Run this command again, this time with OTP_CONFIRM=TRUE appended" 88 | @echo "to the command in the terminal" 89 | endif 90 | 91 | clean: 92 | -rm -fR .dep $(BUILD_DIR) 93 | 94 | .PHONY: all flash gdb dfu bmp clean erase_config 95 | 96 | -------------------------------------------------------------------------------- /Firmware/MotorControl/example.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "", 4 | "id": 0, 5 | "type": "json" 6 | }, 7 | { 8 | "name": "subscriptions", 9 | "id": 1, 10 | "type": "int32[]" 11 | }, 12 | { 13 | "name": "motor0", 14 | "id": 2, 15 | "type": "tree", 16 | "content": [ 17 | { 18 | "name": "pos_setpoint", 19 | "id": 3, 20 | "type": "float", 21 | "access": "rw" 22 | }, 23 | { 24 | "name": "pos_gain", 25 | "id": 4, 26 | "type": "float", 27 | "access": "rw" 28 | }, 29 | { 30 | "name": "vel_setpoint", 31 | "id": 5, 32 | "type": "float", 33 | "access": "rw" 34 | } 35 | ] 36 | } 37 | ] -------------------------------------------------------------------------------- /Firmware/MotorControl/low_level.h: -------------------------------------------------------------------------------- 1 | /* Define to prevent recursive inclusion -------------------------------------*/ 2 | #ifndef __LOW_LEVEL_H 3 | #define __LOW_LEVEL_H 4 | 5 | #ifndef __ODRIVE_MAIN_H 6 | #error "This file should not be included directly. Include odrive_main.h instead." 7 | #endif 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* Includes ------------------------------------------------------------------*/ 14 | #include 15 | #include 16 | #include 17 | 18 | /* Exported types ------------------------------------------------------------*/ 19 | /* Exported constants --------------------------------------------------------*/ 20 | /* Exported variables --------------------------------------------------------*/ 21 | extern float vbus_voltage; 22 | extern bool brake_resistor_armed; 23 | /* Exported macro ------------------------------------------------------------*/ 24 | /* Exported functions --------------------------------------------------------*/ 25 | 26 | void safety_critical_arm_motor_pwm(Motor& motor); 27 | bool safety_critical_disarm_motor_pwm(Motor& motor); 28 | void safety_critical_apply_motor_pwm_timings(Motor& motor, uint16_t timings[3]); 29 | void safety_critical_arm_brake_resistor(); 30 | void safety_critical_disarm_brake_resistor(); 31 | void safety_critical_apply_brake_resistor_timings(uint32_t low_off, uint32_t high_on); 32 | 33 | // called from STM platform code 34 | extern "C" { 35 | void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected); 36 | void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected); 37 | void tim_update_cb(TIM_HandleTypeDef* htim); 38 | } 39 | 40 | // Initalisation 41 | void start_adc_pwm(); 42 | void start_pwm(TIM_HandleTypeDef* htim); 43 | void sync_timers(TIM_HandleTypeDef* htim_a, TIM_HandleTypeDef* htim_b, 44 | uint16_t TIM_CLOCKSOURCE_ITRx, uint16_t count_offset); 45 | void start_general_purpose_adc(); 46 | 47 | float get_adc_voltage(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin); 48 | 49 | void update_brake_current(); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif //__LOW_LEVEL_H 56 | -------------------------------------------------------------------------------- /Firmware/MotorControl/nvm.h: -------------------------------------------------------------------------------- 1 | /* Define to prevent recursive inclusion -------------------------------------*/ 2 | #ifndef __NVML_H 3 | #define __NVM_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* Includes ------------------------------------------------------------------*/ 10 | #include 11 | #include 12 | 13 | /* Exported types ------------------------------------------------------------*/ 14 | /* Exported constants --------------------------------------------------------*/ 15 | /* Exported variables --------------------------------------------------------*/ 16 | /* Exported macro ------------------------------------------------------------*/ 17 | /* Exported functions --------------------------------------------------------*/ 18 | 19 | int NVM_init(void); 20 | int NVM_erase(void); 21 | size_t NVM_get_max_read_length(void); 22 | size_t NVM_get_max_write_length(void); 23 | int NVM_read(size_t offset, uint8_t *data, size_t length); 24 | int NVM_start_write(size_t length); 25 | int NVM_write(size_t offset, uint8_t *data, size_t length); 26 | int NVM_commit(void); 27 | void NVM_demo(void); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif //__NVM_H -------------------------------------------------------------------------------- /Firmware/MotorControl/sensorless_estimator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "odrive_main.h" 3 | 4 | SensorlessEstimator::SensorlessEstimator() 5 | { 6 | // Calculate pll gains 7 | // This calculation is currently identical to the PLL in Encoder 8 | float pll_bandwidth = 1000.0f; // [rad/s] 9 | pll_kp_ = 2.0f * pll_bandwidth; 10 | 11 | // Critically damped 12 | pll_ki_ = 0.25f * (pll_kp_ * pll_kp_); 13 | } 14 | 15 | bool SensorlessEstimator::update() { 16 | // Algorithm based on paper: Sensorless Control of Surface-Mount Permanent-Magnet Synchronous Motors Based on a Nonlinear Observer 17 | // http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf 18 | // In particular, equation 8 (and by extension eqn 4 and 6). 19 | 20 | // The V_alpha_beta applied immedietly prior to the current measurement associated with this cycle 21 | // is the one computed two cycles ago. To get the correct measurement, it was stored twice: 22 | // once by final_v_alpha/final_v_beta in the current control reporting, and once by V_alpha_beta_memory. 23 | 24 | // Check that we don't get problems with discrete time approximation 25 | if (!(current_meas_period * pll_kp_ < 1.0f)) { 26 | error_ |= ERROR_UNSTABLE_GAIN; 27 | return false; 28 | } 29 | 30 | // Clarke transform 31 | float I_alpha_beta[2] = { 32 | -axis_->motor_.current_meas_.phB - axis_->motor_.current_meas_.phC, 33 | one_by_sqrt3 * (axis_->motor_.current_meas_.phB - axis_->motor_.current_meas_.phC)}; 34 | 35 | // Swap sign of I_beta if motor is reversed 36 | I_alpha_beta[1] *= axis_->motor_.config_.direction; 37 | 38 | // alpha-beta vector operations 39 | float eta[2]; 40 | for (int i = 0; i <= 1; ++i) { 41 | // y is the total flux-driving voltage (see paper eqn 4) 42 | float y = -axis_->motor_.config_.phase_resistance * I_alpha_beta[i] + V_alpha_beta_memory_[i]; 43 | // flux dynamics (prediction) 44 | float x_dot = y; 45 | // integrate prediction to current timestep 46 | flux_state_[i] += x_dot * current_meas_period; 47 | 48 | // eta is the estimated permanent magnet flux (see paper eqn 6) 49 | eta[i] = flux_state_[i] - axis_->motor_.config_.phase_inductance * I_alpha_beta[i]; 50 | } 51 | 52 | // Non-linear observer (see paper eqn 8): 53 | float pm_flux_sqr = pm_flux_linkage_ * pm_flux_linkage_; 54 | float est_pm_flux_sqr = eta[0] * eta[0] + eta[1] * eta[1]; 55 | float bandwidth_factor = 1.0f / pm_flux_sqr; 56 | float eta_factor = 0.5f * (observer_gain_ * bandwidth_factor) * (pm_flux_sqr - est_pm_flux_sqr); 57 | 58 | static float eta_factor_avg_test = 0.0f; 59 | eta_factor_avg_test += 0.001f * (eta_factor - eta_factor_avg_test); 60 | 61 | // alpha-beta vector operations 62 | for (int i = 0; i <= 1; ++i) { 63 | // add observer action to flux estimate dynamics 64 | float x_dot = eta_factor * eta[i]; 65 | // convert action to discrete-time 66 | flux_state_[i] += x_dot * current_meas_period; 67 | // update new eta 68 | eta[i] = flux_state_[i] - axis_->motor_.config_.phase_inductance * I_alpha_beta[i]; 69 | } 70 | 71 | // Flux state estimation done, store V_alpha_beta for next timestep 72 | V_alpha_beta_memory_[0] = axis_->motor_.current_control_.final_v_alpha; 73 | V_alpha_beta_memory_[1] = axis_->motor_.current_control_.final_v_beta * axis_->motor_.config_.direction; 74 | 75 | // PLL 76 | // TODO: the PLL part has some code duplication with the encoder PLL 77 | // predict PLL phase with velocity 78 | pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * pll_vel_); 79 | // update PLL phase with observer permanent magnet phase 80 | phase_ = fast_atan2(eta[1], eta[0]); 81 | float delta_phase = wrap_pm_pi(phase_ - pll_pos_); 82 | pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * pll_kp_ * delta_phase); 83 | // update PLL velocity 84 | pll_vel_ += current_meas_period * pll_ki_ * delta_phase; 85 | 86 | return true; 87 | }; 88 | -------------------------------------------------------------------------------- /Firmware/MotorControl/sensorless_estimator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __SENSORLESS_ESTIMATOR_HPP 2 | #define __SENSORLESS_ESTIMATOR_HPP 3 | 4 | class SensorlessEstimator { 5 | public: 6 | enum Error_t { 7 | ERROR_NONE = 0, 8 | ERROR_UNSTABLE_GAIN = 0x01, 9 | }; 10 | 11 | SensorlessEstimator(); 12 | 13 | bool update(); 14 | 15 | Axis* axis_ = nullptr; // set by Axis constructor 16 | 17 | // TODO: expose on protocol 18 | Error_t error_ = ERROR_NONE; 19 | float phase_ = 0.0f; // [rad] 20 | float pll_pos_ = 0.0f; // [rad] 21 | float pll_vel_ = 0.0f; // [rad/s] 22 | float pll_kp_ = 0.0f; // [rad/s / rad] 23 | float pll_ki_ = 0.0f; // [(rad/s^2) / rad] 24 | float observer_gain_ = 1000.0f; // [rad/s] 25 | float flux_state_[2] = {0.0f, 0.0f}; // [Vs] 26 | float V_alpha_beta_memory_[2] = {0.0f, 0.0f}; // [V] 27 | float pm_flux_linkage_ = 1.58e-3f; // [V / (rad/s)] { 5.51328895422 / ( * ) } 28 | bool estimator_good_ = false; 29 | 30 | // Communication protocol definitions 31 | auto make_protocol_definitions() { 32 | return make_protocol_member_list( 33 | make_protocol_property("error", &error_), 34 | make_protocol_property("phase", &phase_), 35 | make_protocol_property("pll_pos", &pll_pos_), 36 | make_protocol_property("pll_vel", &pll_vel_), 37 | make_protocol_property("pll_kp", &pll_kp_), 38 | make_protocol_property("pll_ki", &pll_ki_) 39 | ); 40 | } 41 | }; 42 | 43 | DEFINE_ENUM_FLAG_OPERATORS(SensorlessEstimator::Error_t) 44 | 45 | #endif /* __SENSORLESS_ESTIMATOR_HPP */ 46 | -------------------------------------------------------------------------------- /Firmware/MotorControl/utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __UTILS_H 3 | #define __UTILS_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | /** 13 | * @brief Flash size register address 14 | */ 15 | #define ID_FLASH_ADDRESS (0x1FFF7A22) 16 | 17 | /** 18 | * @brief Device ID register address 19 | */ 20 | #define ID_DBGMCU_IDCODE (0xE0042000) 21 | 22 | /** 23 | * "Returns" the device signature 24 | * 25 | * Possible returns: 26 | * - 0x0413: STM32F405xx/07xx and STM32F415xx/17xx) 27 | * - 0x0419: STM32F42xxx and STM32F43xxx 28 | * - 0x0423: STM32F401xB/C 29 | * - 0x0433: STM32F401xD/E 30 | * - 0x0431: STM32F411xC/E 31 | * 32 | * Returned data is in 16-bit mode, but only bits 11:0 are valid, bits 15:12 are always 0. 33 | * Defined as macro 34 | */ 35 | #define STM_ID_GetSignature() ((*(uint16_t *)(ID_DBGMCU_IDCODE)) & 0x0FFF) 36 | 37 | /** 38 | * "Returns" the device revision 39 | * 40 | * Revisions possible: 41 | * - 0x1000: Revision A 42 | * - 0x1001: Revision Z 43 | * - 0x1003: Revision Y 44 | * - 0x1007: Revision 1 45 | * - 0x2001: Revision 3 46 | * 47 | * Returned data is in 16-bit mode. 48 | */ 49 | #define STM_ID_GetRevision() (*(uint16_t *)(ID_DBGMCU_IDCODE + 2)) 50 | 51 | /** 52 | * "Returns" the Flash size 53 | * 54 | * Returned data is in 16-bit mode, returned value is flash size in kB (kilo bytes). 55 | */ 56 | #define STM_ID_GetFlashSize() (*(uint16_t *)(ID_FLASH_ADDRESS)) 57 | 58 | #ifdef M_PI 59 | #undef M_PI 60 | #endif 61 | #define M_PI 3.14159265358979323846f 62 | 63 | #define MACRO_MAX(x, y) (((x) > (y)) ? (x) : (y)) 64 | #define MACRO_MIN(x, y) (((x) < (y)) ? (x) : (y)) 65 | 66 | static const float one_by_sqrt3 = 0.57735026919f; 67 | static const float two_by_sqrt3 = 1.15470053838f; 68 | static const float sqrt3_by_2 = 0.86602540378f; 69 | 70 | //beware of inserting large values! 71 | static inline float wrap_pm(float x, float pm_range) { 72 | while (x >= pm_range) x -= (2.0f * pm_range); 73 | while (x < -pm_range) x += (2.0f * pm_range); 74 | return x; 75 | } 76 | 77 | //beware of inserting large angles! 78 | static inline float wrap_pm_pi(float theta) { 79 | return wrap_pm(theta, M_PI); 80 | } 81 | 82 | // like fmodf, but always positive 83 | static inline float fmodf_pos(float x, float y) { 84 | float out = fmodf(x, y); 85 | if (out < 0.0f) 86 | out += y; 87 | return out; 88 | } 89 | 90 | // Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta 91 | // as per the magnitude invariant clarke transform 92 | // The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 93 | // Returns 0 on success, and -1 if the input was out of range 94 | int SVM(float alpha, float beta, float* tA, float* tB, float* tC); 95 | 96 | float fast_atan2(float y, float x); 97 | int mod(int dividend, int divisor); 98 | 99 | uint32_t deadline_to_timeout(uint32_t deadline_ms); 100 | uint32_t timeout_to_deadline(uint32_t timeout_ms); 101 | 102 | int is_in_the_future(uint32_t time_ms); 103 | 104 | uint32_t micros(void); 105 | 106 | void delay_us(uint32_t us); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif //__UTILS_H 113 | -------------------------------------------------------------------------------- /Firmware/Tupfile.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/Tupfile.ini -------------------------------------------------------------------------------- /Firmware/adctest.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | adchist = [(0, 137477), 6 | (1, 98524), 7 | (2, 71744), 8 | (3, 60967), 9 | (4, 44372), 10 | (5, 46348), 11 | (6, 19944), 12 | (7, 10092), 13 | (8, 13713), 14 | (9, 11182), 15 | (10, 6903), 16 | (11, 4072), 17 | (12, 2642), 18 | (13, 968), 19 | (14, 296), 20 | (15, 166), 21 | (16, 17), 22 | (17, 2), 23 | (-1, 39662), 24 | (-2, 43502), 25 | (-3, 57596), 26 | (-4, 33915), 27 | (-5, 25611), 28 | (-6, 10880), 29 | (-7, 8237), 30 | (-8, 3518), 31 | (-9, 4789), 32 | (-10, 4689), 33 | (-11, 6345), 34 | (-12, 3901), 35 | (-13, 5781), 36 | (-14, 4803), 37 | (-15, 6428), 38 | (-16, 3563), 39 | (-17, 4478), 40 | (-18, 976), 41 | (-19, 491)] 42 | 43 | adchist.sort() 44 | 45 | adchist = np.array(adchist) 46 | 47 | plt.figure() 48 | plt.bar(adchist[:,0], adchist[:,1]) 49 | plt.show() -------------------------------------------------------------------------------- /Firmware/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Builds the firmware with the configuration specified by 3 | # environment variables named CONFIG_... 4 | # If DEPLOY is set, the deliverables are copied to Firmware/deploy/* 5 | # with the suffix $DEPLOY 6 | set -euo pipefail 7 | 8 | THIS_DIR="$(dirname "$0")" 9 | cd "$THIS_DIR" 10 | 11 | # Treat warnings as errors 12 | export CONFIG_STRICT=true 13 | 14 | # Write all environment variables that start with "CONFIG_" to tup.config 15 | rm -rdf build 16 | mkdir -p build 17 | env | grep ^CONFIG > tup.config 18 | tup generate ./tup_build.sh 19 | bash -xe ./tup_build.sh 20 | 21 | # Deploy 22 | if ! [ -z ${DEPLOY+x} ]; then 23 | mkdir -p deploy 24 | cp build/ODriveFirmware.elf deploy/ODriveFirmware_"$DEPLOY".elf 25 | cp build/ODriveFirmware.hex deploy/ODriveFirmware_"$DEPLOY".hex 26 | fi 27 | -------------------------------------------------------------------------------- /Firmware/communication/ascii_protocol.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ASCII_PROTOCOL_H 2 | #define __ASCII_PROTOCOL_H 3 | 4 | 5 | /* Includes ------------------------------------------------------------------*/ 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* Exported types ------------------------------------------------------------*/ 13 | /* Exported constants --------------------------------------------------------*/ 14 | /* Exported variables --------------------------------------------------------*/ 15 | /* Exported macro ------------------------------------------------------------*/ 16 | /* Exported functions --------------------------------------------------------*/ 17 | 18 | /* Exported functions --------------------------------------------------------*/ 19 | void ASCII_protocol_parse_stream(const uint8_t* buffer, size_t len, StreamSink& response_channel); 20 | 21 | 22 | #endif /* __ASCII_PROTOCOL_H */ 23 | -------------------------------------------------------------------------------- /Firmware/communication/communication.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMANDS_H 2 | #define COMMANDS_H 3 | 4 | // TODO: resolve assert 5 | #define assert(expr) 6 | 7 | #ifdef __cplusplus 8 | 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #endif 14 | 15 | #include 16 | 17 | extern osThreadId comm_thread; 18 | 19 | extern const uint8_t hw_version_major; 20 | extern const uint8_t hw_version_minor; 21 | extern const uint8_t hw_version_variant; 22 | 23 | void init_communication(void); 24 | void communication_task(void * ctx); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | #endif /* COMMANDS_H */ 31 | -------------------------------------------------------------------------------- /Firmware/communication/interface_can.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_CAN_HPP 2 | #define __INTERFACE_CAN_HPP 3 | 4 | #include "fibre/protocol.hpp" 5 | #include 6 | #include 7 | 8 | struct CAN_context { 9 | CAN_HandleTypeDef *handle = nullptr; 10 | uint8_t node_id = 0; 11 | uint64_t serial_number = 0; 12 | 13 | uint32_t node_ids_in_use_0[4]; // 128 bits (indicate if a node ID was in use up to 1 second ago) 14 | uint32_t node_ids_in_use_1[4]; // 128 bits (indicats if a node ID was in use 1-2 seconds ago) 15 | 16 | uint32_t last_heartbeat_mailbox = 0; 17 | uint32_t tx_msg_cnt = 0; 18 | uint32_t node_id_expiry = 0; 19 | 20 | uint8_t node_id_rng_state = 0; 21 | 22 | osSemaphoreId sem_send_heartbeat; 23 | 24 | // count occurrence various callbacks 25 | uint32_t TxMailboxCompleteCallbackCnt = 0; 26 | uint32_t TxMailboxAbortCallbackCnt = 0; 27 | int RxFifo0MsgPendingCallbackCnt = 0; 28 | int RxFifo0FullCallbackCnt = 0; 29 | int RxFifo1MsgPendingCallbackCnt = 0; 30 | int RxFifo1FullCallbackCnt = 0; 31 | int SleepCallbackCnt = 0; 32 | int WakeUpFromRxMsgCallbackCnt = 0; 33 | int ErrorCallbackCnt = 0; 34 | 35 | uint32_t received_msg_cnt = 0; 36 | uint32_t received_ack = 0; 37 | uint32_t unexpected_errors = 0; 38 | uint32_t unhandled_messages = 0; 39 | 40 | auto make_protocol_definitions() { 41 | return make_protocol_member_list( 42 | make_protocol_ro_property("node_id", &node_id), 43 | make_protocol_ro_property("TxMailboxCompleteCallbackCnt", &TxMailboxCompleteCallbackCnt), 44 | make_protocol_ro_property("TxMailboxAbortCallbackCnt", &TxMailboxAbortCallbackCnt), 45 | make_protocol_ro_property("received_msg_cnt", &received_msg_cnt), 46 | make_protocol_ro_property("received_ack", &received_ack), 47 | make_protocol_ro_property("unexpected_errors", &unexpected_errors), 48 | make_protocol_ro_property("unhandled_messages", &unhandled_messages) 49 | ); 50 | } 51 | }; 52 | 53 | bool start_can_server(CAN_context& ctx, CAN_TypeDef *hcan, uint64_t serial_number); 54 | 55 | #endif // __INTERFACE_CAN_HPP 56 | -------------------------------------------------------------------------------- /Firmware/communication/interface_i2c.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "interface_i2c.h" 3 | #include "fibre/protocol.hpp" 4 | 5 | #include 6 | 7 | #define I2C_RX_BUFFER_SIZE 128 8 | #define I2C_RX_BUFFER_PREAMBLE_SIZE 4 9 | #define I2C_TX_BUFFER_SIZE 128 10 | 11 | I2CStats_t i2c_stats_ = {0}; 12 | 13 | static uint8_t i2c_rx_buffer[I2C_RX_BUFFER_PREAMBLE_SIZE + I2C_RX_BUFFER_SIZE]; 14 | static uint8_t i2c_tx_buffer[I2C_TX_BUFFER_SIZE]; 15 | 16 | class I2CSender : public PacketSink { 17 | public: 18 | int process_packet(const uint8_t* buffer, size_t length) { 19 | if (length >= 2 && (length - 2) <= sizeof(i2c_tx_buffer)) 20 | memcpy(i2c_tx_buffer, buffer + 2, length - 2); 21 | return 0; 22 | } 23 | size_t get_free_space() { return SIZE_MAX; } 24 | } i2c1_packet_output; 25 | BidirectionalPacketBasedChannel i2c1_channel(i2c1_packet_output); 26 | 27 | void start_i2c_server() { 28 | // CAN H = SDA 29 | // CAN L = SCL 30 | HAL_I2C_EnableListen_IT(&hi2c1); 31 | } 32 | 33 | void i2c_handle_packet(I2C_HandleTypeDef *hi2c) { 34 | size_t received = sizeof(i2c_rx_buffer) - hi2c->XferCount; 35 | if (received > I2C_RX_BUFFER_PREAMBLE_SIZE) { 36 | i2c_stats_.rx_cnt++; 37 | 38 | write_le(0, i2c_rx_buffer); // hallucinate seq-no (not needed for I2C) 39 | i2c_rx_buffer[2] = i2c_rx_buffer[4]; // endpoint-id = I2C register address 40 | i2c_rx_buffer[3] = i2c_rx_buffer[5] | 0x80; // MSB must be 1 41 | size_t expected_bytes = (TX_BUF_SIZE - 2) < I2C_TX_BUFFER_SIZE ? (TX_BUF_SIZE - 2) : I2C_TX_BUFFER_SIZE; 42 | write_le(expected_bytes, i2c_rx_buffer + 4); // hallucinate maximum number of expected response bytes 43 | 44 | i2c1_channel.process_packet(i2c_rx_buffer, received); 45 | 46 | // reset receive buffer 47 | hi2c->pBuffPtr = I2C_RX_BUFFER_PREAMBLE_SIZE + i2c_rx_buffer; 48 | hi2c->XferCount = sizeof(i2c_rx_buffer) - I2C_RX_BUFFER_PREAMBLE_SIZE; 49 | } 50 | 51 | 52 | if (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN) 53 | hi2c->State = HAL_I2C_STATE_LISTEN; 54 | } 55 | 56 | 57 | void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { 58 | i2c_handle_packet(hi2c); 59 | // restart listening for address 60 | HAL_I2C_EnableListen_IT(hi2c); 61 | } 62 | 63 | void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { 64 | i2c_stats_.addr_match_cnt += 1; 65 | 66 | i2c_handle_packet(hi2c); 67 | 68 | if (TransferDirection == I2C_DIRECTION_TRANSMIT) { 69 | HAL_I2C_Slave_Sequential_Receive_IT(hi2c, 70 | I2C_RX_BUFFER_PREAMBLE_SIZE + i2c_rx_buffer, 71 | sizeof(i2c_rx_buffer) - I2C_RX_BUFFER_PREAMBLE_SIZE, I2C_FIRST_AND_LAST_FRAME); 72 | } else { 73 | HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2c_tx_buffer, sizeof(i2c_tx_buffer), I2C_FIRST_AND_LAST_FRAME); 74 | } 75 | } 76 | 77 | void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { 78 | // ignore NACK errors 79 | if (!(hi2c->ErrorCode & (~HAL_I2C_ERROR_AF))) 80 | return; 81 | 82 | i2c_stats_.error_cnt += 1; 83 | 84 | // Continue listening 85 | HAL_I2C_EnableListen_IT(hi2c); 86 | } 87 | -------------------------------------------------------------------------------- /Firmware/communication/interface_i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_I2C_HPP 2 | #define __INTERFACE_I2C_HPP 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | struct I2CStats_t { 11 | uint8_t addr; 12 | uint32_t addr_match_cnt; 13 | uint32_t rx_cnt; 14 | uint32_t error_cnt; 15 | }; 16 | 17 | extern I2CStats_t i2c_stats_; 18 | 19 | void start_i2c_server(void); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif // __INTERFACE_I2C_HPP 26 | -------------------------------------------------------------------------------- /Firmware/communication/interface_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_UART_HPP 2 | #define __INTERFACE_UART_HPP 3 | 4 | #ifdef __cplusplus 5 | #include "fibre/protocol.hpp" 6 | extern StreamSink* uart4_stream_output_ptr; 7 | 8 | extern "C" { 9 | #endif 10 | 11 | #include 12 | 13 | extern osThreadId uart_thread; 14 | 15 | void start_uart_server(void); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif // __INTERFACE_UART_HPP 22 | -------------------------------------------------------------------------------- /Firmware/communication/interface_usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_USB_HPP 2 | #define __INTERFACE_USB_HPP 3 | 4 | #ifdef __cplusplus 5 | #include "fibre/protocol.hpp" 6 | extern StreamSink* usb_stream_output_ptr; 7 | 8 | extern "C" { 9 | #endif 10 | 11 | #include 12 | #include 13 | 14 | extern osThreadId usb_thread; 15 | 16 | typedef struct { 17 | uint32_t rx_cnt; 18 | uint32_t tx_cnt; 19 | uint32_t tx_overrun_cnt; 20 | } USBStats_t; 21 | 22 | extern USBStats_t usb_stats_; 23 | 24 | void usb_process_packet(uint8_t *buf, uint32_t len, uint8_t endpoint_pair); 25 | void start_usb_server(void); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif // __INTERFACE_USB_HPP 32 | -------------------------------------------------------------------------------- /Firmware/fibre/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .Trash* 3 | /build 4 | /.tup 5 | -------------------------------------------------------------------------------- /Firmware/fibre/cpp/include/fibre/crc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CRC_HPP 2 | #define __CRC_HPP 3 | 4 | #include 5 | #include 6 | 7 | // Calculates an arbitrary CRC for one byte. 8 | // Adapted from https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code 9 | template 10 | static T calc_crc(T remainder, uint8_t value) { 11 | constexpr T BIT_WIDTH = (CHAR_BIT * sizeof(T)); 12 | constexpr T TOPBIT = ((T)1 << (BIT_WIDTH - 1)); 13 | 14 | // Bring the next byte into the remainder. 15 | remainder ^= (value << (BIT_WIDTH - 8)); 16 | 17 | // Perform modulo-2 division, a bit at a time. 18 | for (uint8_t bit = 8; bit; --bit) { 19 | if (remainder & TOPBIT) { 20 | remainder = (remainder << 1) ^ POLYNOMIAL; 21 | } else { 22 | remainder = (remainder << 1); 23 | } 24 | } 25 | 26 | return remainder; 27 | } 28 | 29 | template 30 | static T calc_crc(T remainder, const uint8_t* buffer, size_t length) { 31 | while (length--) 32 | remainder = calc_crc(remainder, *(buffer++)); 33 | return remainder; 34 | } 35 | 36 | template 37 | static uint8_t calc_crc8(uint8_t remainder, uint8_t value) { 38 | return calc_crc(remainder, value); 39 | } 40 | 41 | template 42 | static uint16_t calc_crc16(uint16_t remainder, uint8_t value) { 43 | return calc_crc(remainder, value); 44 | } 45 | 46 | template 47 | static uint8_t calc_crc8(uint8_t remainder, const uint8_t* buffer, size_t length) { 48 | return calc_crc(remainder, buffer, length); 49 | } 50 | 51 | template 52 | static uint16_t calc_crc16(uint16_t remainder, const uint8_t* buffer, size_t length) { 53 | return calc_crc(remainder, buffer, length); 54 | } 55 | 56 | #endif /* __CRC_HPP */ 57 | -------------------------------------------------------------------------------- /Firmware/fibre/cpp/include/fibre/posix_tcp.hpp: -------------------------------------------------------------------------------- 1 | 2 | #include "protocol.hpp" 3 | 4 | int serve_on_tcp(unsigned int port); 5 | -------------------------------------------------------------------------------- /Firmware/fibre/cpp/include/fibre/posix_udp.hpp: -------------------------------------------------------------------------------- 1 | 2 | #include "protocol.hpp" 3 | 4 | int serve_on_udp(unsigned int port); 5 | -------------------------------------------------------------------------------- /Firmware/fibre/cpp/package.lua: -------------------------------------------------------------------------------- 1 | 2 | tup.include('../tupfiles/build.lua') 3 | 4 | fibre_package = define_package{ 5 | sources={'protocol.cpp', 'posix_tcp.cpp', 'posix_udp.cpp'}, 6 | libs={'pthread'}, 7 | headers={'include'} 8 | } 9 | -------------------------------------------------------------------------------- /Firmware/fibre/cpp/posix_tcp.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | #define TCP_RX_BUF_LEN 512 15 | 16 | class TCPStreamSink : public StreamSink { 17 | public: 18 | TCPStreamSink(int socket_fd) : 19 | socket_fd_(socket_fd) 20 | {} 21 | 22 | int process_bytes(const uint8_t* buffer, size_t length, size_t* processed_bytes) { 23 | int bytes_sent = send(socket_fd_, buffer, length, 0); 24 | if (processed_bytes) 25 | *processed_bytes = (bytes_sent == -1) ? 0 : bytes_sent; 26 | return (bytes_sent == -1) ? -1 : 0; 27 | } 28 | 29 | size_t get_free_space() { return SIZE_MAX; } 30 | 31 | private: 32 | int socket_fd_; 33 | }; 34 | 35 | 36 | int serve_client(int sock_fd) { 37 | uint8_t buf[TCP_RX_BUF_LEN]; 38 | 39 | // initialize output stack for this client 40 | TCPStreamSink tcp_packet_output(sock_fd); 41 | StreamBasedPacketSink packet2stream(tcp_packet_output); 42 | BidirectionalPacketBasedChannel channel(packet2stream); 43 | 44 | StreamToPacketSegmenter stream2packet(channel); 45 | 46 | // now listen for it 47 | for (;;) { 48 | memset(buf, 0, sizeof(buf)); 49 | // returns as soon as there is some data 50 | ssize_t n_received = recv(sock_fd, buf, sizeof(buf), 0); 51 | 52 | // -1 indicates error and 0 means that the client gracefully terminated 53 | if (n_received == -1 || n_received == 0) { 54 | close(sock_fd); 55 | return n_received; 56 | } 57 | 58 | // input processing stack 59 | size_t processed = 0; 60 | stream2packet.process_bytes(buf, n_received, &processed); 61 | } 62 | } 63 | 64 | // function to check if a worker thread handling a single client is done 65 | template 66 | bool future_is_ready(std::future& t){ 67 | return t.wait_for(std::chrono::seconds(0)) == std::future_status::ready; 68 | } 69 | 70 | int serve_on_tcp(unsigned int port) { 71 | struct sockaddr_in6 si_me, si_other; 72 | int s; 73 | 74 | 75 | if ((s=socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) { 76 | return -1; 77 | } 78 | 79 | memset((char *) &si_me, 0, sizeof(si_me)); 80 | si_me.sin6_family = AF_INET6; 81 | si_me.sin6_port = htons(port); 82 | si_me.sin6_flowinfo = 0; 83 | si_me.sin6_addr = in6addr_any; 84 | if (bind(s, reinterpret_cast(&si_me), sizeof(si_me)) == -1) { 85 | return -1; 86 | } 87 | 88 | listen(s, 128); // make this socket a passive socket 89 | std::vector> serv_pool; 90 | for (;;) { 91 | memset(&si_other, 0, sizeof(si_other)); 92 | 93 | socklen_t silen = sizeof(si_other); 94 | // TODO: Add a limit on accepting connections 95 | int client_portal_fd = accept(s, reinterpret_cast(&si_other), &silen); // blocking call 96 | serv_pool.push_back(std::async(std::launch::async, serve_client, client_portal_fd)); 97 | // do a little clean up on the pool 98 | for (std::vector>::iterator it = serv_pool.end()-1; it >= serv_pool.begin(); --it) { 99 | if (future_is_ready(*it)) { 100 | // we can erase this thread 101 | serv_pool.erase(it); 102 | } 103 | } 104 | } 105 | 106 | close(s); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /Firmware/fibre/cpp/posix_udp.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #define UDP_RX_BUF_LEN 512 11 | #define UDP_TX_BUF_LEN 512 12 | 13 | 14 | class UDPPacketSender : public PacketSink { 15 | public: 16 | UDPPacketSender(int socket_fd, struct sockaddr_in6 *si_other) : 17 | _socket_fd(socket_fd), 18 | _si_other(si_other) 19 | {} 20 | 21 | size_t get_mtu() { return UDP_TX_BUF_LEN; } 22 | 23 | int process_packet(const uint8_t* buffer, size_t length) { 24 | // cannot send partial packets 25 | if (length > get_mtu()) 26 | return -1; 27 | 28 | int status = sendto(_socket_fd, buffer, length, 0, reinterpret_cast(_si_other), sizeof(*_si_other)); 29 | return (status == -1) ? -1 : 0; 30 | } 31 | 32 | private: 33 | int _socket_fd; 34 | struct sockaddr_in6 *_si_other; 35 | }; 36 | 37 | 38 | 39 | int serve_on_udp(unsigned int port) { 40 | struct sockaddr_in6 si_me, si_other; 41 | int s; 42 | socklen_t slen = sizeof(si_other); 43 | uint8_t buf[UDP_RX_BUF_LEN]; 44 | 45 | if ((s=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) 46 | return -1; 47 | 48 | memset((char *) &si_me, 0, sizeof(si_me)); 49 | si_me.sin6_family = AF_INET6; 50 | si_me.sin6_port = htons(port); 51 | si_me.sin6_flowinfo = 0; 52 | si_me.sin6_addr= in6addr_any; 53 | if (bind(s, reinterpret_cast(&si_me), sizeof(si_me)) == -1) 54 | return -1; 55 | 56 | for (;;) { 57 | ssize_t n_received = recvfrom(s, buf, sizeof(buf), 0, reinterpret_cast(&si_other), &slen); 58 | if (n_received == -1) 59 | return -1; 60 | //printf("Received packet from %s:%d\nData: %s\n\n", 61 | // inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf); 62 | 63 | UDPPacketSender udp_packet_output(s, &si_other); 64 | BidirectionalPacketBasedChannel udp_channel(udp_packet_output); 65 | udp_channel.process_packet(buf, n_received); 66 | } 67 | 68 | close(s); 69 | } 70 | 71 | -------------------------------------------------------------------------------- /Firmware/fibre/python/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Python Distribution / packaging 3 | .Python 4 | /dist/ 5 | /*.egg-info/ 6 | /MANIFEST 7 | 8 | # PyInstaller 9 | # Usually these files are written by a python script from a template 10 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 11 | *.manifest 12 | *.spec 13 | 14 | # Installer logs 15 | pip-log.txt 16 | pip-delete-this-directory.txt 17 | -------------------------------------------------------------------------------- /Firmware/fibre/python/fibre/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .discovery import find_any, find_all 3 | from .utils import Event, Logger 4 | from .protocol import ChannelBrokenException, ChannelDamagedException 5 | from .shell import launch_shell 6 | -------------------------------------------------------------------------------- /Firmware/fibre/python/fibre/tcp_transport.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import socket 4 | import time 5 | import traceback 6 | import fibre.protocol 7 | from fibre.utils import wait_any 8 | 9 | def noprint(x): 10 | pass 11 | 12 | class TCPTransport(fibre.protocol.StreamSource, fibre.protocol.StreamSink): 13 | def __init__(self, dest_addr, dest_port, logger): 14 | # TODO: FIXME: use IPv6 15 | # Problem: getaddrinfo fails if the resolver returns an 16 | # IPv4 address, but we are using AF_INET6 17 | #family = socket.AF_INET6 if socket.has_ipv6 else socket.AF_INET 18 | family = socket.AF_INET 19 | self.sock = socket.socket(family, socket.SOCK_STREAM) 20 | # TODO: Determine the right address to use from the list 21 | self.target = socket.getaddrinfo(dest_addr, dest_port, family)[0][4] 22 | # TODO: this blocks until a connection is established, or the system cancels it 23 | self.sock.connect(self.target) 24 | 25 | def process_bytes(self, buffer): 26 | self.sock.send(buffer) 27 | 28 | def get_bytes(self, n_bytes, deadline): 29 | """ 30 | Returns n bytes unless the deadline is reached, in which case the bytes 31 | that were read up to that point are returned. If deadline is None the 32 | function blocks forever. A deadline before the current time corresponds 33 | to non-blocking mode. 34 | """ 35 | # convert deadline to seconds (floating point) 36 | deadline = None if deadline is None else max(deadline - time.monotonic(), 0) 37 | self.sock.settimeout(deadline) 38 | try: 39 | data = self.sock.recv(n_bytes, socket.MSG_WAITALL) # receive n_bytes 40 | return data 41 | except socket.timeout: 42 | # if we got a timeout data will still be none, so we call recv again 43 | # this time in non blocking state and see if we can get some data 44 | try: 45 | return self.sock.recv(n_bytes, socket.MSG_DONTWAIT) 46 | except socket.timeout: 47 | raise TimeoutError 48 | 49 | def get_bytes_or_fail(self, n_bytes, deadline): 50 | result = self.get_bytes(n_bytes, deadline) 51 | if len(result) < n_bytes: 52 | raise TimeoutError("expected {} bytes but got only {}".format(n_bytes, len(result))) 53 | return result 54 | 55 | 56 | 57 | def discover_channels(path, serial_number, callback, cancellation_token, channel_termination_token, logger): 58 | """ 59 | Tries to connect to a TCP server based on the path spec. 60 | This function blocks until cancellation_token is set. 61 | Channels spawned by this function run until channel_termination_token is set. 62 | """ 63 | try: 64 | dest_addr = ':'.join(path.split(":")[:-1]) 65 | dest_port = int(path.split(":")[-1]) 66 | except (ValueError, IndexError): 67 | raise Exception('"{}" is not a valid TCP destination. The format should be something like "localhost:1234".' 68 | .format(path)) 69 | 70 | while not cancellation_token.is_set(): 71 | try: 72 | tcp_transport = fibre.tcp_transport.TCPTransport(dest_addr, dest_port, logger) 73 | stream2packet_input = fibre.protocol.PacketFromStreamConverter(tcp_transport) 74 | packet2stream_output = fibre.protocol.StreamBasedPacketSink(tcp_transport) 75 | channel = fibre.protocol.Channel( 76 | "TCP device {}:{}".format(dest_addr, dest_port), 77 | stream2packet_input, packet2stream_output, 78 | channel_termination_token, logger) 79 | except: 80 | #logger.debug("TCP channel init failed. More info: " + traceback.format_exc()) 81 | pass 82 | else: 83 | callback(channel) 84 | wait_any(None, cancellation_token, channel._channel_broken) 85 | time.sleep(1) 86 | -------------------------------------------------------------------------------- /Firmware/fibre/python/fibre/udp_transport.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import socket 4 | import time 5 | import traceback 6 | import fibre.protocol 7 | from fibre.utils import wait_any 8 | 9 | def noprint(x): 10 | pass 11 | 12 | class UDPTransport(fibre.protocol.PacketSource, fibre.protocol.PacketSink): 13 | def __init__(self, dest_addr, dest_port, logger): 14 | # TODO: FIXME: use IPv6 15 | # Problem: getaddrinfo fails if the resolver returns an 16 | # IPv4 address, but we are using AF_INET6 17 | #family = socket.AF_INET6 if socket.has_ipv6 else socket.AF_INET 18 | family = socket.AF_INET 19 | self.sock = socket.socket(family, socket.SOCK_DGRAM) 20 | # TODO: Determine the right address to use from the list 21 | self.target = socket.getaddrinfo(dest_addr,dest_port, family)[0][4] 22 | 23 | def process_packet(self, buffer): 24 | self.sock.sendto(buffer, self.target) 25 | 26 | def get_packet(self, deadline): 27 | # TODO: implement deadline 28 | data, _ = self.sock.recvfrom(1024) 29 | return data 30 | 31 | def discover_channels(path, serial_number, callback, cancellation_token, channel_termination_token, logger): 32 | """ 33 | Tries to connect to a UDP server based on the path spec. 34 | This function blocks until cancellation_token is set. 35 | Channels spawned by this function run until channel_termination_token is set. 36 | """ 37 | try: 38 | dest_addr = ':'.join(path.split(":")[:-1]) 39 | dest_port = int(path.split(":")[-1]) 40 | except (ValueError, IndexError): 41 | raise Exception('"{}" is not a valid UDP destination. The format should be something like "localhost:1234".' 42 | .format(path)) 43 | 44 | while not cancellation_token.is_set(): 45 | try: 46 | udp_transport = fibre.udp_transport.UDPTransport(dest_addr, dest_port, logger) 47 | channel = fibre.protocol.Channel( 48 | "UDP device {}:{}".format(dest_addr, dest_port), 49 | udp_transport, udp_transport, 50 | channel_termination_token, logger) 51 | except: 52 | logger.debug("UDP channel init failed. More info: " + traceback.format_exc()) 53 | pass 54 | else: 55 | callback(channel) 56 | wait_any(None, cancellation_token, channel._channel_broken) 57 | time.sleep(1) 58 | -------------------------------------------------------------------------------- /Firmware/fibre/python/setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | This script is used to deploy the Fibre python library to PyPi 3 | so that users can install them easily with 4 | "pip install fibre" 5 | 6 | To install the package and its dependencies locally, run: 7 | sudo pip install -r requirements.txt 8 | 9 | To build and package the python tools into a tar archive: 10 | python setup.py sdist 11 | 12 | Warning: Before you proceed, be aware that you can upload a 13 | specific version only once ever. After that you need to increment 14 | the hotfix number. Deleting the release manually on the PyPi 15 | website does not help. 16 | 17 | Use TestPyPi while developing. 18 | 19 | To build, package and upload the python tools to TestPyPi, run: 20 | python setup.py sdist upload -r pypitest 21 | To make a real release ensure you're at the release commit 22 | and then run the above command without the "test" (so just "pypi"). 23 | 24 | To install a prerelease version from test index: 25 | sudo pip install --pre --index-url https://test.pypi.org/simple/ --no-cache-dir fibre 26 | 27 | 28 | PyPi access requires that you have set up ~/.pypirc with your 29 | PyPi credentials and that your account has the rights 30 | to publish packages with the name fibre. 31 | """ 32 | 33 | # TODO: add additional y/n prompt to prevent from erroneous upload 34 | 35 | from setuptools import setup 36 | import os 37 | import sys 38 | 39 | # Change this if you already uploaded the current 40 | # version but need to release a hotfix 41 | hotfix = 0 42 | 43 | #creating_package = "sdist" in sys.argv 44 | # 45 | ## Load version from Git tag 46 | #import odrive.version 47 | #version = odrive.version.get_version_str(git_only=creating_package) 48 | # 49 | #if creating_package and (hotfix > 0 or not version[-1].isdigit()): 50 | # # Add this for hotfixes 51 | # version += "-" + str(hotfix) 52 | # 53 | # 54 | ## If we're currently creating the package we need to autogenerate 55 | ## a file that contains the version string 56 | #if creating_package: 57 | # version_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'odrive', 'version.txt') 58 | # with open(version_file_path, mode='w') as version_file: 59 | # version_file.write(version) 60 | # 61 | ## TODO: find a better place for this 62 | #if not creating_package: 63 | # import platform 64 | # if platform.system() == 'Linux': 65 | # import odrive.utils 66 | # odrive.utils.setup_udev_rules(odrive.utils.Logger()) 67 | 68 | setup( 69 | name = 'fibre', 70 | packages = ['fibre'], 71 | #scripts = ['..fibre', 'odrivetool.bat', 'odrive_demo.py'], 72 | version = '0.0.1dev0', 73 | description = 'Abstraction layer for painlessly building object oriented distributed systems that just work', 74 | author = 'Samuel Sadok', 75 | author_email = 'samuel.sadok@bluewin.ch', 76 | license='MIT', 77 | url = 'https://github.com/samuelsadok/fibre', 78 | keywords = ['communication', 'transport-layer', 'rpc'], 79 | install_requires = [], 80 | #package_data={'': ['version.txt']}, 81 | classifiers = [], 82 | ) 83 | 84 | # TODO: include README 85 | 86 | ## clean up 87 | #if creating_package: 88 | # os.remove(version_file_path) 89 | -------------------------------------------------------------------------------- /Firmware/fibre/test/Tupfile.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | tup.include('../tupfiles/build.lua') 4 | tup.include('../cpp/package.lua') 5 | 6 | test_server = define_package{ 7 | packages={fibre_package}, 8 | sources={'test_server.cpp'} 9 | } 10 | 11 | unit_tests = define_package{ 12 | packages={fibre_package}, 13 | sources={'run_tests.cpp'} 14 | } 15 | 16 | 17 | toolchain=GCCToolchain('', 'build', {'-O3', '-fvisibility=hidden', '-frename-registers', '-funroll-loops'}, {}) 18 | toolchain=GCCToolchain('', 'build', {'-O3', '-g', '-Wall'}, {}) 19 | --toolchain=GCCToolchain('avr-', {'-Ofast', '-fvisibility=hidden', '-frename-registers', '-funroll-loops', '-I/home/samuel/stlport-avr/stlport'}, {}) 20 | --toolchain=LLVMToolchain('x86_64', {'-O3', '-fno-sanitize=safe-stack', '-fno-stack-protector'}, {'-flto', '-Wl,-s'}) 21 | --toolchain=LLVMToolchain('avr', {'-O3', '-std=gnu++11', '--target=avr', '-fno-sanitize=safe-stack', '-fno-stack-protector', '-I/home/samuel/stlport-avr/stlport'}, {'-flto', '-Wl,-s'}) 22 | 23 | 24 | if tup.getconfig("BUILD_FIBRE_TESTS") == "true" then 25 | build_executable('test_server', test_server, toolchain) 26 | --build_executable('run_tests', unit_tests, toolchain) 27 | end 28 | -------------------------------------------------------------------------------- /Firmware/fibre/test/test_server.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | class TestClass { 13 | public: 14 | float property1; 15 | float property2; 16 | 17 | float set_both(float arg1, float arg2) { 18 | property1 = arg1; 19 | property2 = arg2; 20 | return property1 + property2; 21 | } 22 | 23 | FIBRE_EXPORTS(TestClass, 24 | make_protocol_property("property1", &property1), 25 | make_protocol_property("property2", &property2), 26 | make_protocol_function("set_both", *obj, &TestClass::set_both, "arg1", "arg2") 27 | ); 28 | }; 29 | 30 | 31 | int main() { 32 | printf("Starting Fibre server...\n"); 33 | 34 | TestClass test_object = TestClass(); 35 | 36 | // publish the object on Fibre 37 | auto definitions = test_object.fibre_definitions; 38 | fibre_publish(definitions); 39 | 40 | // Expose Fibre objects on TCP and UDP 41 | std::thread server_thread_tcp(serve_on_tcp, 9910); 42 | std::thread server_thread_udp(serve_on_udp, 9910); 43 | printf("Fibre server started.\n"); 44 | 45 | // Dump property1 value 46 | while (1) { 47 | printf("test_object.property1: %f\n", test_object.property1); 48 | usleep(1000000 / 5); // 5 Hz 49 | } 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /Firmware/fibre/tools/fibre-shell: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Connect to a Fibre-enabled device to play with in the IPython interactive shell. 4 | """ 5 | import argparse 6 | import sys 7 | import os 8 | 9 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/python") 10 | 11 | from fibre import Logger, Event 12 | 13 | # Parse arguments 14 | parser = argparse.ArgumentParser(description='Connect to a fibre-enabled device to play with it in the IPython interactive shell.') 15 | parser.add_argument("-p", "--path", metavar="PATH", action="store", 16 | help="The path(s) where ODrive(s) should be discovered.\n" 17 | "By default the script will connect to any ODrive on USB.\n\n" 18 | "To select a specific USB device:\n" 19 | " --path usb:BUS:DEVICE\n" 20 | "usbwhere BUS and DEVICE are the bus and device numbers as shown in `lsusb`.\n\n" 21 | "To select a specific serial port:\n" 22 | " --path serial:PATH\n" 23 | "where PATH is the path of the serial port. For example \"/dev/ttyUSB0\".\n" 24 | "You can use `ls /dev/tty*` to find the correct port.\n\n" 25 | "You can combine USB and serial specs by separating them with a comma (no space!)\n" 26 | "Example:\n" 27 | " --path usb,serial:/dev/ttyUSB0\n" 28 | "means \"discover any USB device or a serial device on /dev/ttyUSB0\"") 29 | parser.add_argument("-s", "--serial-number", action="store", 30 | help="The 12-digit serial number of the device. " 31 | "This is a string consisting of 12 upper case hexadecimal " 32 | "digits as displayed in lsusb. \n" 33 | " example: 385F324D3037\n" 34 | "You can list all devices connected to USB by running\n" 35 | "(lsusb -d 1209:0d32 -v; lsusb -d 0483:df11 -v) | grep iSerial\n" 36 | "If omitted, any device is accepted.") 37 | parser.add_argument("--no-ipython", action="store_true", 38 | help="Use the regular Python shell " 39 | "instead of the IPython shell, " 40 | "even if IPython is installed.") 41 | parser.add_argument("-v", "--verbose", action="store_true", 42 | help="print debug information") 43 | 44 | parser.set_defaults(path="usb,tcp:localhost:9910") 45 | args = parser.parse_args() 46 | 47 | logger = Logger(verbose=args.verbose) 48 | app_shutdown_token = Event() 49 | 50 | def print_banner(): 51 | pass 52 | 53 | def print_help(args, have_devices): 54 | pass 55 | 56 | import fibre 57 | fibre.launch_shell(args, {}, print_banner, print_help, logger, app_shutdown_token) 58 | -------------------------------------------------------------------------------- /Firmware/find_programmer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | openocd -d3 -f board/stm32f4discovery.cfg -c "hla_serial wrong_serial" 2>&1 | \ 3 | xxd -p | \ 4 | tr -d '\n' | \ 5 | sed -n 's/^.*6e756d6265722027\([0-9a-f]*\)2720646f65736e27.*$/\1/p' | sed -e 's/.\{2\}/\\x&/g'; echo 6 | -------------------------------------------------------------------------------- /Firmware/motor_timing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/Firmware/motor_timing.jpg -------------------------------------------------------------------------------- /Firmware/openocd.gdbinit: -------------------------------------------------------------------------------- 1 | target remote | openocd -f "interface/stlink-v2.cfg" -f "target/stm32f4x_stlink.cfg" -c "gdb_port pipe; log_output openocd.log" 2 | monitor reset halt 3 | -------------------------------------------------------------------------------- /Firmware/tup.config.default: -------------------------------------------------------------------------------- 1 | # Copy this file to tup.config and adapt it to your needs 2 | # make sure this fits your board 3 | #CONFIG_BOARD_VERSION=v3.5-24V 4 | CONFIG_USB_PROTOCOL=native 5 | CONFIG_UART_PROTOCOL=ascii 6 | CONFIG_DEBUG=false 7 | 8 | # Uncomment this to error on compilation warnings 9 | #CONFIG_STRICT=true 10 | -------------------------------------------------------------------------------- /ODrive_Workspace.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "Firmware" 5 | }, 6 | { 7 | "path": "tools" 8 | }, 9 | { 10 | "path": "docs" 11 | }, 12 | { 13 | "path": "/Users/nathan/Documents/QPWoofer" 14 | }, 15 | { 16 | "path": "/Users/nathan/Documents" 17 | } 18 | ], 19 | "settings": { 20 | "files.associations": { 21 | "memory": "cpp", 22 | "utility": "cpp", 23 | "deque": "cpp", 24 | "vector": "cpp", 25 | "array": "cpp", 26 | "*.tcc": "cpp", 27 | "cctype": "cpp", 28 | "clocale": "cpp", 29 | "cstdint": "cpp", 30 | "cstdio": "cpp", 31 | "cstdlib": "cpp", 32 | "cstring": "cpp", 33 | "cwchar": "cpp", 34 | "cwctype": "cpp", 35 | "exception": "cpp", 36 | "functional": "cpp", 37 | "initializer_list": "cpp", 38 | "iosfwd": "cpp", 39 | "istream": "cpp", 40 | "limits": "cpp", 41 | "new": "cpp", 42 | "ostream": "cpp", 43 | "stdexcept": "cpp", 44 | "streambuf": "cpp", 45 | "string_view": "cpp", 46 | "system_error": "cpp", 47 | "tuple": "cpp", 48 | "type_traits": "cpp", 49 | "typeinfo": "cpp", 50 | "algorithm": "cpp", 51 | "chrono": "cpp", 52 | "condition_variable": "cpp", 53 | "future": "cpp", 54 | "unordered_map": "cpp", 55 | "cmath": "cpp" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![ODrive Logo](https://static1.squarespace.com/static/58aff26de4fcb53b5efd2f02/t/59bf2a7959cc6872bd68be7e/1505700483663/Odrive+logo+plus+text+black.png?format=1000w) 2 | 3 | This project is all about accurately driving brushless motors, for cheap. The aim is to make it possible to use inexpensive brushless motors in high performance robotics projects, like [this](https://www.youtube.com/watch?v=WT4E5nb3KtY). 4 | 5 | | Branch | Build Status | 6 | |--------|--------------| 7 | | master | [![Build Status](https://travis-ci.org/madcowswe/ODrive.png?branch=master)](https://travis-ci.org/madcowswe/ODrive) | 8 | | devel | [![Build Status](https://travis-ci.org/madcowswe/ODrive.png?branch=devel)](https://travis-ci.org/madcowswe/ODrive) | 9 | 10 | 11 | Please refer to the [Developer Guide](https://docs.odriverobotics.com/developer-guide.md) to get started with ODrive firmware development. 12 | 13 | 14 | ### Repository Structure 15 | * **Firmware**: ODrive firmware 16 | * **tools**: Python library & tools 17 | * **docs**: Documentation 18 | 19 | ### Other Resources 20 | 21 | * [Main Website](https://www.odriverobotics.com/) 22 | * [User Guide](https://docs.odriverobotics.com/) 23 | * [Forum](https://discourse.odriverobotics.com/) 24 | * [Chat](https://discourse.odriverobotics.com/t/come-chat-with-us/281) 25 | -------------------------------------------------------------------------------- /analysis/cogging_torque/cogging_harmonics.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | encoder_cpr = 2400 6 | stator_slots = 12 7 | pole_pairs = 7 8 | 9 | N = data.size 10 | fft = np.fft.rfft(data) 11 | freq = np.fft.rfftfreq(N, d=1./encoder_cpr) 12 | 13 | harmonics = [0] 14 | harmonics += [(i+1)*stator_slots for i in range(pole_pairs)] 15 | harmonics += [pole_pairs] 16 | harmonics += [(i+1)*2*pole_pairs for i in range(int(stator_slots/4))] 17 | 18 | 19 | fft_sparse = fft.copy() 20 | indicies = np.arange(fft_sparse.size) 21 | mask = [i not in harmonics for i in indicies] 22 | fft_sparse[mask] = 0.0 23 | interp_data = np.fft.irfft(fft_sparse) 24 | 25 | #%% 26 | 27 | #plt.figure() 28 | plt.subplot(3, 1, 1) 29 | plt.plot(data, label='raw') 30 | plt.plot(interp_data, label='selected harmonics IFFT') 31 | plt.title('cogging map') 32 | plt.xlabel('counts') 33 | plt.ylabel('A') 34 | plt.legend(loc='best') 35 | 36 | #plt.figure() 37 | plt.subplot(3, 1, 2) 38 | plt.stem(freq, np.abs(fft)/N, label='raw') 39 | plt.stem(freq[harmonics], np.abs(fft_sparse[harmonics])/N, markerfmt='ro', label='selected harmonics') 40 | plt.title('cogging map spectrum') 41 | plt.xlabel('cycles/turn') 42 | plt.ylabel('A') 43 | plt.legend(loc='best') 44 | 45 | #plt.figure() 46 | plt.subplot(3, 1, 3) 47 | plt.stem(freq, np.abs(fft)/N, label='raw') 48 | plt.stem(freq[harmonics], np.abs(fft_sparse[harmonics])/N, markerfmt='ro', label='selected harmonics') 49 | plt.title('cogging map spectrum') 50 | plt.xlabel('cycles/turn') 51 | plt.ylabel('A') 52 | plt.legend(loc='best') -------------------------------------------------------------------------------- /analysis/motor_analysis/350kvTP.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/analysis/motor_analysis/350kvTP.PNG -------------------------------------------------------------------------------- /analysis/motor_analysis/350kvVelli.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/analysis/motor_analysis/350kvVelli.PNG -------------------------------------------------------------------------------- /analysis/motor_analysis/VelliPlot.m: -------------------------------------------------------------------------------- 1 | % limits 2 | Imax = 64; %A 3 | Umax = 22; %V 4 | Irange = 100; %A. Range for plotting current 5 | omegaMax = 2000; %rad/s mechanical. For plotting voltage ellipses 6 | omegastep = 200; %rad/s mechanical. For plotting voltage ellipses 7 | 8 | 9 | %% 10 | %350 kv motor 11 | lambda = 2.24/1000; 12 | L = 23e-6; 13 | R = 32e-3; 14 | pp = 7; Poles = pp*2; 15 | Ld = L; 16 | Lq = L; 17 | 18 | % %% 19 | % % Donkey 20 | % kv = 820; 21 | % lambda = 60/(kv*2*pi*pp*sqrt(3)); 22 | % L = 8e-6; %Guess! TODO: measure 23 | % R = 30e-3; %Guess! TODO: measure 24 | % pp = 7; Poles = pp*2; 25 | % Ld = L; 26 | % Lq = L; 27 | 28 | %% 29 | Istep = Irange/400; 30 | Idplt = repmat(-Irange:Istep:Irange,801,1); 31 | Iqplt = repmat((-Irange:Istep:Irange)',1,801); 32 | UmaxSq = (Umax/sqrt(3))^2; 33 | 34 | t = linspace(0,2*pi); 35 | IdMaxt = Imax*cos(t); 36 | IqMaxt = Imax*sin(t); 37 | 38 | %% 39 | figure(1) 40 | plot(IdMaxt, IqMaxt); 41 | 42 | hold on; 43 | 44 | %Plot torque 45 | %[c,h] = contour(Idplt,Iqplt, (Poles/2).*(3/2).*(lambda.*Iqplt + (Ld-Lq).*Iqplt.*Idplt), -5:0.25:5); 46 | %clabel(c,h,'LabelSpacing',500); 47 | 48 | %Plot voltage ellipses 49 | EllRHS = Ld^2.*(lambda/Ld + Idplt).^2 + Lq^2.*Iqplt.^2; 50 | omegaAtEllipse = sqrt(UmaxSq./EllRHS); 51 | [c,h] = contour(Idplt,Iqplt, omegaAtEllipse./(Poles/2), 0:omegastep:omegaMax); 52 | clabel(c,h,'LabelSpacing',500); 53 | xlabel 'Id (A)' 54 | ylabel 'Iq (A)' 55 | colormap(jet) 56 | c = colorbar; 57 | %c.Label.String = 'Speed (rad/s)'; 58 | ylabel(c,'Speed (mechanical rad/s)') 59 | grid on 60 | axis equal 61 | 62 | %plot infinite speed point 63 | plot(-lambda/Ld, 0, 'r*'); 64 | 65 | hold off; 66 | 67 | %% 68 | figure(2) 69 | 70 | %fw range 71 | t = linspace(pi/2,pi); 72 | IdMaxt = Imax*cos(t); 73 | IqMaxt = Imax*sin(t); 74 | Tmaxt = (Poles/2).*(3/2).*(lambda.*IqMaxt + (Ld-Lq).*IqMaxt.*IdMaxt); 75 | EllRHSmaxt = Ld^2.*(lambda/Ld + IdMaxt).^2 + Lq^2.*IqMaxt.^2; 76 | omegamaxt = sqrt(UmaxSq./EllRHSmaxt); 77 | 78 | %MTPA range 79 | MTPAmaxtId = 0; %TODO make work for salient machines 80 | MTPAmaxtIq = Imax; 81 | TmaxtMTPA = (Poles/2).*(3/2).*(lambda.*MTPAmaxtIq + (Ld-Lq).*MTPAmaxtIq.*MTPAmaxtId); 82 | Tmaxt = [repmat(TmaxtMTPA, 1, 100) Tmaxt]; 83 | omegamaxt = [linspace(0,omegamaxt(1)) omegamaxt]; 84 | 85 | %Present mechanical speed 86 | omegamaxt = omegamaxt./(Poles/2); 87 | 88 | Pmaxt = Tmaxt.*omegamaxt; 89 | 90 | %plotyy(t, Tmaxt, t, omegamaxt); 91 | %plotyy(t, Tmaxt, t, Pmaxt); 92 | %plotyy(t, Pmaxt, t, omegamaxt); 93 | 94 | h = plotyy(omegamaxt, Tmaxt, omegamaxt, Pmaxt); 95 | grid on 96 | xlabel 'Speed (mechanical rad/s)' 97 | ylabel 'Torque (Nm)' 98 | ylabel(h(2), 'Power (W)'); -------------------------------------------------------------------------------- /analysis/numeric_path_opt/Main.m: -------------------------------------------------------------------------------- 1 | %Params 2 | AccelPerA = 3000; 3 | phaseR = 0.033; 4 | Ts = 0.001; 5 | N = 50; 6 | thetaFinal = 200; 7 | x0 = [0;0]; 8 | 9 | %system definition 10 | %X = [theta; omega] 11 | Ac = [0 1; 12 | 0 0]; 13 | Bc = [0; 14 | AccelPerA]; 15 | C = 0; 16 | D = 0; 17 | 18 | SYSC = ss(Ac, Bc, [], []); 19 | SYSD = c2d(SYSC, Ts, 'zoh'); 20 | [Phi, Gamma] = predictionmatrices(SYSD.a, SYSD.b, SYSD.c, N); 21 | 22 | Df = Gamma(end-1:end,:); 23 | ff = [thetaFinal; 0]; 24 | 25 | H = 2*eye(N)*(3/2)*phaseR*Ts; 26 | [u, fval] = quadprog(H,[],[],[],Df,ff); 27 | 28 | xv = reshape(Gamma*u, 2,N)'; 29 | x = xv(:,1); 30 | v = xv(:,2); 31 | 32 | kv350_lambda = 2.2e-3; 33 | power = u.*v.*(3/2)*kv350_lambda; 34 | 35 | Vbus = 24; 36 | Ib = power/Vbus; 37 | Im = u; 38 | duty = Ib./Im; 39 | CapIsqr = (duty.*(Ib-Im)).^2 + ((1-duty).*Ib).^2; 40 | CapIrms = sqrt(sum(CapIsqr)/N); 41 | CapR = 0.08; 42 | Ncaps = 8; 43 | Cappow = (CapIrms/Ncaps)^2 * CapR 44 | -------------------------------------------------------------------------------- /analysis/numeric_path_opt/predictionmatrices.m: -------------------------------------------------------------------------------- 1 | function [Phi, Gamma, Lambda] = predictionmatrices(A, B, C, N) 2 | %UNTITLED2 Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | n = size(A,1); 6 | Atilde = [A; zeros((N-1)*n, n)]; 7 | k = [zeros(n, N*n); -kron(eye(N-1), A) zeros((N-1)*n,n)] + eye(N*n); 8 | 9 | Phi = k\Atilde; 10 | Gamma = k\kron(eye(N), B); 11 | Lambda = kron(eye(N), C); 12 | 13 | end 14 | 15 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.odriverobotics.com -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins 3 | gem 'jekyll-redirect-from' 4 | -------------------------------------------------------------------------------- /docs/_config.yaml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal 2 | exclude: [ruby-bundle] 3 | plugins: 4 | - jekyll-redirect-from 5 | google_analytics: UA-93396600-3 6 | -------------------------------------------------------------------------------- /docs/_data/index.yaml: -------------------------------------------------------------------------------- 1 | 2 | # This data could theoretically be retrieved directly from the md files: 3 | # https://jekyllrb.com/tutorials/navigation/#scenario-8-retrieving-items-based-on-front-matter-properties 4 | 5 | sections: 6 | - title: For Users 7 | docs: 8 | - title: Getting Started 9 | url: / 10 | - title: ODrive Tool 11 | url: odrivetool 12 | - title: Parameters & Commands 13 | url: commands 14 | - title: Interfaces 15 | url: interfaces 16 | - title: Encoders 17 | url: encoders 18 | - title: Troubleshooting 19 | url: troubleshooting 20 | - title: For ODrive Developers 21 | docs: 22 | - title: Firmware Developer Guide 23 | url: developer-guide 24 | - title: Configuring Visual Studio Code 25 | url: configuring-vscode 26 | - title: Configuring Eclipse 27 | url: configuring-eclipse 28 | -------------------------------------------------------------------------------- /docs/ascii-protocol.md: -------------------------------------------------------------------------------- 1 | 2 | # ASCII Protocol 3 | 4 | ## How to send commands 5 | 6 | * **Via USB:** 7 | * **Windows:** Use the Zadig utility to set the ODrive's driver to "usbser". Windows will then make the device available as COM port. You can use [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) to manually send commands or open the COM port using your favorite programming language 8 | * **Linux/macOS:** Run `/dev/tty*` to list all serial ports. The ODrive will show up as `/dev/ttyACM0` on Linux and `/dev/tty.usbmodem[...]` on macOS. Once you know the name, you can use `screen /dev/ttyACM0` (with the correct name) to send commands manually or open the device using your favorite programming language. Serial ports on Unix can be opened, written to and read from like a normal file. 9 | * **Via UART:** Connect the ODrive's TX (GPIO1) to your host's RX. Connect your ODrive's RX (GPIO2) to your host's TX. The logic level of the ODrive is 3.3V. 10 | * **Arduino:** You can use the [ODrive Arduino library](https://github.com/madcowswe/ODriveArduino) to talk to the ODrive. 11 | * **Windows/Linux/macOS:** You can use an FTDI USB-UART cable to connect to the ODrive. 12 | 13 | ## Command format 14 | 15 | The ASCII protocol is human-readable and line-oriented, with each line having the following format: 16 | 17 | ``` 18 | command *42 ; comment [new line character] 19 | ``` 20 | 21 | * `*42` stands for a GCode compatible checksum and can be omitted. If and only if a checksum is provided, the device will also include a checksum in the response, if any. 22 | * comments are supported for GCode compatibility 23 | * the command is interpreted once the new-line character is encountered 24 | 25 | ## Command Reference 26 | 27 | #### Motor Position command 28 | ``` 29 | p motor position velocity_ff current_ff 30 | ``` 31 | * `p` for position 32 | * `motor` is the motor number, `0` or `1`. 33 | * `position` is the desired position, in encoder counts. 34 | * `velocity_ff` is the velocity feed-forward term, in counts/s (optional). 35 | * `current_ff` is the current feed-forward term, in A (optional). 36 | 37 | Example: `p 0 -20000 0 0` 38 | 39 | Note that if you don't know what feed-forward is or what it's used for, simply omit it. 40 | 41 | 42 | #### Motor Velocity command 43 | ``` 44 | v motor velocity current_ff 45 | ``` 46 | * `v` for velocity 47 | * `motor` is the motor number, `0` or `1`. 48 | * `velocity` is the desired velocity in counts/s. 49 | * `current_ff` is the current feed-forward term, in A (optional). 50 | 51 | Example: `v 0 1000 0` 52 | 53 | Note that if you don't know what feed-forward is or what it's used for, simply omit it. 54 | 55 | #### Motor Current command 56 | ``` 57 | c motor current 58 | ``` 59 | * `c` for current 60 | * `motor` is the motor number, `0` or `1`. 61 | * `current` is the desired current in A. 62 | 63 | #### Parameter reading/writing 64 | 65 | Not all parameters can be accessed via the ASCII protocol but at least all parameters with float and integer type are supported. 66 | 67 | * Reading: 68 | ``` 69 | r [property] 70 | ``` 71 | * `property` name of the property, as seen in ODrive Tool 72 | * response: text representation of the requested value 73 | * Example: `r vbus_voltage` => response: `24.087744` 74 | * Writing: 75 | ``` 76 | w [property] [value] 77 | ``` 78 | * `property` name of the property, as seen in ODrive Tool 79 | * `value` text representation of the value to be written 80 | * Example: `w axis0.controller.pos_setpoint -123.456` 81 | -------------------------------------------------------------------------------- /docs/configuring-eclipse.md: -------------------------------------------------------------------------------- 1 | # Setting up Eclipse development environment 2 | 3 | ## Install 4 | * Install [Eclipse IDE for C/C++ Developers](http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/neon3) 5 | * Install the [OpenOCD Eclipse plugin](http://gnuarmeclipse.github.io/plugins/install/) 6 | 7 | ## Import project 8 | * File -> Import -> C/C++ -> Existing Code as Makefile Project 9 | * Browse for existing code location, find the OdriveFirmware root. 10 | * In the Toolchain options, select `Cross GCC` 11 | * Hit Finish 12 | * Build the project (press ctrl-B) 13 | 14 | ![Toolchain options](screenshots/CodeAsMakefile.png "Toolchain options") 15 | 16 | ## Load the launch configuration 17 | * File -> Import -> Run/Debug -> Launch Configurations -> Next 18 | * Highlight (don't tick) the OdriveFirmare folder in the left column 19 | * Tick OdriveFirmware.launch in the right column 20 | * Hit Finish 21 | 22 | ![Launch Configurations](screenshots/ImportLaunch.png "Launch Configurations") 23 | 24 | ## Launch! 25 | * Make sure the programmer is connected to the board as per [Flashing the firmware](#flashing-the-firmware). 26 | * Press the down-arrow of the debug symbol in the toolbar, and hit Debug Configurations 27 | * You can also hit Run -> Debug Configurations 28 | * Highlight the debug configuration you imported, called OdriveFirmware. If you do not see the imported launch configuration rename your project to `ODriveFirmware` or edit the launch configuration to match your project name by unfiltering unavailable projects: 29 | 30 | ![Launch Configuration Filters](screenshots/LaunchConfigFilter.png "Launch Configuration Filters") 31 | 32 | * Hit Debug 33 | * Eclipse should flash the board for you and the program should start halted on the first instruction in `Main` 34 | * Set beakpoints, step, hit Resume, etc. 35 | * Make some cool features! ;D -------------------------------------------------------------------------------- /docs/configuring-vscode.md: -------------------------------------------------------------------------------- 1 | # Configuring Visual Studio Code 2 | 3 | VSCode is the recommended IDE for working with the ODrive codebase. It is a light-weight text editor with Git integration and GDB debugging functionality. 4 | 5 | Before doing the VSCode setup, make sure you've installed all of your [prerequisites](README.md#installing-prerequisites) 6 | 7 | ## Setup Procedure 8 | 1. Clone the ODrive repository 9 | 1. [Download VSCode](https://code.visualstudio.com/download) 10 | 1. Open VSCode 11 | 1. Install extensions. This can be done directly from VSCode (Ctrl+Shift+X) 12 | * Required extensions: 13 | * C/C++ 14 | * Recommended Extensions: 15 | * Cortex-Debug 16 | * vscode-icons 17 | * Code Outline 18 | * Include Autocomplete 19 | * Path Autocomplete 20 | * Auto Comment Blocks 21 | 1. Restart VSCode 22 | 1. Open the VSCode Workspace file, which is located in the root of the ODrive repository. It is called `ODrive_Workspace.code-workspace`. The first time you open it, VSCode will install some dependencies. If it fails, you may need to [change your proxy settings](https://code.visualstudio.com/docs/getstarted/settings). 23 | 24 | You should now be ready to compile and test the ODrive project. 25 | 26 | ## Building the Firmware 27 | * Tasks -> Run Build Task 28 | 29 | A terminal window will open with your native shell. VSCode is configured to run the command `make -j4` in this terminal. 30 | 31 | ## Flashing the Firmware 32 | * Tasks -> Run Task -> flash 33 | 34 | A terminal window will open with your native shell. VSCode is configured to run the command `make flash` in this terminal. 35 | 36 | If the flashing worked, you can connect to the board using the [odrivetool](../docs/getting-started#start-odrivetool). 37 | 38 | ## Debugging 39 | An extension called Cortex-Debug has recently been released which is designed specifically for debugging ARM Cortex projects. You can read more on Cortex-Debug here: https://github.com/Marus/cortex-debug 40 | 41 | Note: If developing on Windows, you should have `arm-none-eabi-gdb` and `openOCD` on your PATH. 42 | 43 | * Make sure you have the Firmware folder as your active folder 44 | * Flash the board with the newest code (starting debug session doesn't do this) 45 | * Debug -> Start Debugging (or press F5) 46 | * The processor will reset and halt. 47 | * Set your breakpoints. Note: you can only set breakpoints when the processor is halted, if you set them during run mode, they won't get applied. 48 | * Run (F5) 49 | * Stepping over/in/out, restarting, and changing breakpoints can be done by first pressing the "pause" (F6) button at the top the screen. 50 | * When done debugging, simply stop (Shift+F5) the debugger. It will kill your openOCD process too. 51 | 52 | ## Cleaning the Build 53 | This sometimes needs to be done if you change branches. 54 | * Open a terminal (View -> Integrated Terminal) and enter `make clean` -------------------------------------------------------------------------------- /docs/encoders.md: -------------------------------------------------------------------------------- 1 | # Encoders 2 | 3 | ## Known and Supported Encoders 4 | Contributions to this table highly encouraged! 5 | 6 | Encoder|Manufacturer|Output|Index|Max CPR|Max RPM|Voltage|Supported|Price|Link|Datasheet 7 | :--|:--|:--|:-:|:-:|:-:|:-:|:--|:--|:--|:-- 8 | AMT102|CUI|Quadrature|Yes|8192 (2048 * 4)|-|5V|Yes|-|-|- 9 | AMT203|CUI|Quadrature + Absolute|Yes|4096 (1024 * 4)|-|5V|Quadrature Only|-|-|- 10 | AS5047P|AMS|Quadrature + Absolute|Yes|4096 (1024 * 4)|28k|3.3V or 5V|Quadrature Only|-|-|- 11 | E6B2-CWZ6C|Omron|Quadrature|Yes|8000 (2000 * 4)|-|5-24V|Yes|-|-|[Datasheet](http://www.ia.omron.com/products/family/487/) 12 | J733|-|Quadrature|No|2400 (600 * 4)|-|5-24V|Yes|-|-|- 13 | 14 | ## Encoder Calibration 15 | 16 | All encoder types that are currently supported require the ODrive to do some sort of encoder calibration at every startup before you can run the motor control. Take this into account when designing your application. 17 | 18 | 19 | ### Encoder without index signal 20 | 21 | During encoder offset calibration the rotor must be allowed to rotate without any biased load during startup. That means mass and weak friction loads are fine, but gravity or spring loads are not okay. 22 | 23 | In the `odrivetool`, type `.encoder.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION` Enter. 24 | 25 | To verify everything went well, check the following variables: 26 | 27 | * `.error` should be 0. 28 | * `.encoder.config.offset` - This should print a number, like -326 or 1364. 29 | * `.motor.config.direction` - This should print 1 or -1. 30 | 31 | ### Encoder with index signal 32 | If you have an encoder with an index (Z) signal, you may avoid having to do the offset calibration on every startup, and instead use the index signal to re-sync the encoder to a stored calibration. 33 | 34 | Below are the steps to do the one-time calibration and configuration. Note that you can follow these steps with one motor at a time, or all motors together, as you wish. 35 | 36 | * Since you will only do this once, it is recommended that you mechanically disengage the motor from anything other than the encoder, so it can spin freely. 37 | * Set `.encoder.config.use_index` to `True`. 38 | * Run `.requested_state = AXIS_STATE_ENCODER_INDEX_SEARCH`. This will make the motor turn in one direction until it finds the encoder index. 39 | * Follow the calibration instructions for an [encoder without index signal](#encoder-without-index-signal). 40 | * Set `.encoder.config.pre_calibrated` to `True` to confirm that the offset is valid with respect to the index pulse. 41 | * If you would like to search for the index at startup, set `.config.startup_encoder_index_search` to `True`. 42 | * If you'd rather do it manually, just run `.requested_state = AXIS_STATE_ENCODER_INDEX_SEARCH` on every bootup. 43 | * If you are looking to start your machine as quickly as possible on bootup, also set `.motor.config.pre_calibrated` to `True` to save the current motor calibration and avoid doing it again on bootup. 44 | * Save the configuration by typing `.save_configuration()` Enter. 45 | 46 | That's it, now on every reboot the motor will turn in one direction until it finds the encoder index. 47 | 48 | * If you wish to scan for the index pulse in the other direction (if for example your axis usually starts close to a hard-stop), you can set a negative value in `.encoder.config.idx_search_speed`. 49 | * If your motor has problems reaching the index location due to the mechanical load, you can increase `.motor.config.calibration_current`. 50 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/docs/favicon.ico -------------------------------------------------------------------------------- /docs/protocol.md: -------------------------------------------------------------------------------- 1 | 2 | # ODrive Communication Protocol # 3 | 4 | Communicating with an ODrive consists of a series of endpoint operations. 5 | An endpoint can theoretically be any kind data serialized in any way. 6 | There is a default seralization implementation for POD types; for custom types 7 | you must (de)seralize yourself. In the future we may provide a default seralizer 8 | for stucts. 9 | The available endpoints can be enumerated by reading the JSON from endpoint 0 10 | and can theoretically be different for each communication interface (they are not in practice). 11 | 12 | Each endpoint operation can send bytes to one endpoint (referenced by it's ID) 13 | and at the same time receive bytes from the same endpoint. The semantics of 14 | these payloads are specific to each endpoint's type, the name of which is 15 | indicated in the JSON. 16 | 17 | For instance an int32 endpoint's input and output is a 4 byte little endian 18 | representation. In general the convention for combined read/write requests is 19 | _exchange_, i.e. the returned value is the old value. Custom endpoint handlers 20 | may be non-compliant. 21 | 22 | There is a packet based version and a stream based variant of the protocol. Each 23 | variant is employed as appropriate. For instance USB runs the packet based variant 24 | by default while UART runs the stream based variant. 25 | 26 | 27 | ## Packet format ## 28 | We will call the ODrive "server" and the PC "client". A request is a message 29 | from the PC to the ODrive and a response is a message from the ODrive to the 30 | PC. 31 | 32 | Each request-response transaction corresponds to a single endpoint operation. 33 | 34 | __Request__ 35 | 36 | - __Bytes 0, 1__ Sequence number, MSB = 0 37 | - Currently the server does not care about ordering and does not filter resent messages. 38 | - __Bytes 2, 3__ Endpoint ID 39 | - The IDs of all endpoints can be obtained from the JSON definition. The JSON definition can be obtained by reading from endpoint 0. 40 | If (and only if) the MSB is set to 1 the client expects a response for this request. 41 | - __Bytes 4, 5__ Expected response size 42 | - The number of bytes that should be returned to the client. If the client doesn't need any response data, it can set this value to 0. The operation will still be acknowledged if the 43 | MSB in EndpointID is set. 44 | - __Bytes 6 to N-3__ Payload 45 | - The length of the payload is determined by the total packet size. The format of the payload depends on the endpoint type. The endpoint type can be obtained from the JSON definition. 46 | - __Bytes N-2, N-1__ 47 | - For endpoint 0: Protocol version (currently 1). A server shall ignore packets with other values. 48 | - For all other endpoints: The CRC16 calculated over the JSON definition. The CRC16 init value is the protocol version (currently 1). A server shall ignore packets that set this field incorrectly. See protocol.hpp for CRC details. 49 | 50 | __Response__ 51 | 52 | - __Bytes 0, 1__ Sequence number, MSB = 1 53 | - The sequence number of the request to which this is the response. 54 | - __Bytes 2, 3__ Payload 55 | - The length of the payload tends to be equal to the number of expected bytes as indicated 56 | in the request. The server must not expect the client to accept more bytes than it requested. 57 | 58 | ## Stream format ## 59 | The stream based format is just a wrapper for the packet format. 60 | 61 | - __Byte 0__ Sync byte `0xAA` 62 | - __Bytes 1, 2__ Packet length 63 | - Currently both parties shall only emit and accept values of 0 through 127. 64 | - __Bytes 3__ CRC8 of bytes 0 through 2 65 | - See protocol.hpp for CRC details. 66 | - __Bytes 4 to N-3__ Packet 67 | - __Bytes N-2, N-1__ CRC16 68 | - See protocol.hpp for CRC details. 69 | -------------------------------------------------------------------------------- /docs/screenshots/CodeAsMakefile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/docs/screenshots/CodeAsMakefile.png -------------------------------------------------------------------------------- /docs/screenshots/ImportLaunch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/docs/screenshots/ImportLaunch.png -------------------------------------------------------------------------------- /docs/screenshots/LaunchConfigFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/docs/screenshots/LaunchConfigFilter.png -------------------------------------------------------------------------------- /docs/stlink-wiring-cropped.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nate711/ODrive/ec25d02f7036b0d7eff010fdc516bd0054a86c56/docs/stlink-wiring-cropped.jpg -------------------------------------------------------------------------------- /docs/test.md: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /docs/testing.md: -------------------------------------------------------------------------------- 1 | # Automated Testing 2 | 3 | This section describes how to use the automated testing facilities. 4 | You don't have to do this as an end user. 5 | 6 | They test the following aspects: 7 | - System functions (communication interfaces, configuration storage) 8 | - Functionality of the motor controller and state machine 9 | - High speed and high load conditions 10 | 11 | The testing facility consists of the following components: 12 | * **Test rig:** In the simplest case this can be a single ODrive with a single motor and encoder pair. Can also be multiple ODrives with multiple axes, some of which may be mechanically coupled. 13 | * **Test host:** The PC on which the test script runs. All ODrives must be connected to the test host via USB. 14 | * **test-rig.yaml:** Describes your test rig. Make sure all values are correct. Incorrect values may physically break or fry your test setup. 15 | * **run_tests.py:** This is the main script that runs all the tests. 16 | 17 | ## How to run 18 | 19 | Example: 20 | 21 | ``` 22 | ./run_tests.py --skip-boring-tests --ignore top-odrive.yellow bottom-odrive.yellow 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ## Error codes 4 | If your ODrive is not working as expected, run `odrivetool` and type `hex(.error)` Enter where `` is the axis that isn't working. This will display a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) representation of the error code. Each bit represents one error flag. 5 | 6 |
Example
7 | 8 | Say you got this error output: 9 | ```python 10 | In [1]: hex(odrv0.axis0.error) 11 | Out[1]: '0x6' 12 | ``` 13 | 14 | Written in binary, the number `0x6` corresponds to `110`, that means bits 1 and 2 are set (counting starts at 0). 15 | 16 | Looking at the reference below, this means that both `ERROR_DC_BUS_UNDER_VOLTAGE` and `ERROR_DC_BUS_OVER_VOLTAGE` occurred. 17 | 18 |
19 | 20 | There is a slight chance that the values here are out of sync with the actual firmware. To be completely sure, check the linked definition in the source code. 21 | 22 | ### Axis error flags 23 | 24 | Defined [here](../Firmware/MotorControl/axis.hpp) 25 | 26 | 0. `ERROR_INVALID_STATE` 27 | 1. `ERROR_DC_BUS_UNDER_VOLTAGE` 28 | 2. `ERROR_DC_BUS_OVER_VOLTAGE` 29 | 3. `ERROR_CURRENT_MEASUREMENT_TIMEOUT` 30 | 4. `ERROR_BRAKE_RESISTOR_DISARMED` 31 | 5. `ERROR_MOTOR_DISARMED` 32 | 6. `ERROR_MOTOR_FAILED` (check `.motor.error` for more details) 33 | 7. `ERROR_SENSORLESS_ESTIMATOR_FAILED` (check `.sensorless_estimator.error` for more details) 34 | 8. `ERROR_ENCODER_FAILED` (check `.encoder.error` for more details) 35 | 9. `ERROR_CONTROLLER_FAILED` 36 | 10. `ERROR_POS_CTRL_DURING_SENSORLESS` 37 | 38 | ### Motor error flags 39 | 40 | Defined [here](../Firmware/MotorControl/motor.hpp) 41 | 42 | 0. `ERROR_PHASE_RESISTANCE_OUT_OF_RANGE` 43 | 1. `ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE` 44 | 2. `ERROR_ADC_FAILED` 45 | 3. [`ERROR_DRV_FAULT`](#drv-fault) 46 | 4. `ERROR_CONTROL_DEADLINE_MISSED` 47 | 5. `ERROR_NOT_IMPLEMENTED_MOTOR_TYPE` 48 | 6. `ERROR_BRAKE_CURRENT_OUT_OF_RANGE` 49 | 7. `ERROR_NUMERICAL` 50 | 51 | ### Encoder error flags 52 | 53 | Defined [here](../Firmware/MotorControl/encoder.hpp) 54 | 55 | 0. `ERROR_NUMERICAL` 56 | 1. `ERROR_CPR_OUT_OF_RANGE` 57 | 2. `ERROR_RESPONSE` 58 | 59 | ### Sensorless estimator error flags 60 | 61 | Defined [here](../Firmware/MotorControl/sensorless_estimator.hpp) 62 | 63 | 0. `ERROR_NUMERICAL` 64 | 65 | 66 | ## DRV fault 67 | 68 | The ODrive v3.4 is known to have a hardware issue whereby the motors would stop operating 69 | when applying high currents to M0. The reported error of both motors in this case 70 | is `ERROR_DRV_FAULT`. 71 | 72 | The conjecture is that the high switching current creates large ripples in the 73 | power supply of the DRV8301 gate driver chips, thus tripping its undervoltage 74 | fault detection. 75 | 76 | * Limit the M0 current to 40A. The lowest current at which the DRV fault was observed is 45A on one test motor and 50A on another test motor. 77 | * Refer to [this post](https://discourse.odriverobotics.com/t/drv-fault-on-odrive-v3-4/558) for instructions for a hardware fix 78 | 79 | 80 | ## USB Connectivity Issues 81 | 82 | * Try turning it off and on again (the ODrive, the script, the PC) 83 | * Make sure you're using the latest firmware and python tools release 84 | * **Linux**: Type `lsusb` to list all USB devices. Verify that your ODrive is listed. 85 | * **Linux**: Make sure you [set up your udev rules](getting-started#downloading-and-installing-tools) correctly. 86 | * **Windows**: Right-click on the start menu and open "Device Manager". Verify that your ODrive is listed. 87 | * **Windows**: Use the [Zadig utility](http://zadig.akeo.ie/) to verify the driver is set to `libusb-win32`. 88 | * Ensure that no other ODrive program is running 89 | * Run `odrivetools` with the `--verbose` option. 90 | * Run `PYUSB_DEBUG=debug odrivetools` to get even more log output. 91 | * If you're a developer you can use Wireshark to capture USB traffic. 92 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Python Distribution / packaging 3 | .Python 4 | #env/ 5 | #build/ 6 | #develop-eggs/ 7 | /dist/ 8 | #downloads/ 9 | #eggs/ 10 | #.eggs/ 11 | #lib/ 12 | #lib64/ 13 | #parts/ 14 | #sdist/ 15 | #var/ 16 | /*.egg-info/ 17 | #.installed.cfg 18 | #*.egg 19 | /MANIFEST 20 | 21 | # PyInstaller 22 | # Usually these files are written by a python script from a template 23 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 24 | *.manifest 25 | *.spec 26 | 27 | # Installer logs 28 | pip-log.txt 29 | pip-delete-this-directory.txt 30 | -------------------------------------------------------------------------------- /tools/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python", 9 | "type": "python", 10 | "request": "launch", 11 | "stopOnEntry": true, 12 | "pythonPath": "${config:python.pythonPath}", 13 | "program": "${file}", 14 | "cwd": "${workspaceRoot}", 15 | "env": {}, 16 | "envFile": "${workspaceRoot}/.env", 17 | "debugOptions": [ 18 | "WaitOnAbnormalExit", 19 | "WaitOnNormalExit", 20 | "RedirectOutput" 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /tools/bandwidthtest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Example usage of the ODrive python library to monitor and control ODrive devices 4 | """ 5 | 6 | from __future__ import print_function 7 | 8 | import odrive 9 | from odrive.enums import * 10 | import time 11 | import math 12 | from fibre import Logger, Event 13 | from odrive.utils import OperationAbortedException 14 | from fibre.protocol import ChannelBrokenException 15 | import sys 16 | import numpy as np 17 | import matplotlib.pyplot as plt 18 | 19 | def get_odrive(shutdown_token): 20 | """ 21 | Look for and return an odrive connected via usb 22 | """ 23 | 24 | print('Looking for ODrive...') 25 | odrv = odrive.find_any(search_cancellation_token=app_shutdown_token, channel_termination_token=app_shutdown_token) 26 | print('Found.') 27 | return odrv 28 | 29 | def main(app_shutdown_token): 30 | """ 31 | !! Main program !! 32 | Looks for odrive, then calibrates, then sets gains, then tests motors 33 | 34 | 35 | WARNING: Saving more than twice per boot will cause a reversion of all changes 36 | """ 37 | 38 | odrv0 = get_odrive(app_shutdown_token) 39 | 40 | input("Press Enter to continue with bandwidth test...") 41 | 42 | ##### Loop Parameters ##### 43 | tspan = 5.0 44 | 45 | update_freq = 800.0 # -> 500Hz gives 0.002s to 0.00207s period 46 | n = int(tspan*update_freq) 47 | start_time = time.time() 48 | intervals = np.zeros((n,)) 49 | prev_time = time.time() 50 | i=0 51 | 52 | ##### Current control parameters ##### 53 | current_commands = np.zeros((n,)) 54 | current_amplitude = 4.0 # amps 55 | min_current = 4.0 56 | current_average = current_amplitude + min_current 57 | signal_freq = 3.0 # Hz 58 | 59 | while(i= start_time + (i+1)*1.0/update_freq: 63 | period = now - prev_time 64 | prev_time = now 65 | intervals[i] = period 66 | 67 | current_command = current_average + current_amplitude * np.sin(2*np.pi*signal_freq*elapsed) 68 | current_command = round(current_command,3) 69 | current_commands[i] = current_command 70 | 71 | 72 | odrv0.axis0.controller.set_current_setpoint(current_command) 73 | 74 | i += 1 75 | if i%10 == 0: 76 | print("I=%s \t t=%s \tdt=%s"%(current_command,elapsed,period)) 77 | 78 | odrv0.axis0.controller.set_current_setpoint(0.0) 79 | # plt.figure() 80 | # plt.plot(current_commands) 81 | # plt.figure() 82 | # plt.plot(intervals) 83 | # plt.show() 84 | 85 | 86 | 87 | app_shutdown_token = Event() 88 | try: 89 | main(app_shutdown_token) 90 | # init_odrive(odrv0) 91 | except OperationAbortedException: 92 | logger.info("Operation aborted.") 93 | finally: 94 | app_shutdown_token.set() 95 | 96 | # encoder calibration 97 | # set use_index ot true 98 | # request encoder_index_search 99 | # pre_calibrated to True 100 | # then change startup to encoder_index_search true 101 | -------------------------------------------------------------------------------- /tools/odrive/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import sys 4 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname( 5 | os.path.dirname(os.path.realpath(__file__)))), 6 | "Firmware", "fibre", "python")) 7 | 8 | # Syntactic sugar to make usage more intuative. 9 | # Try/pass used to break install-time dep issues 10 | try: 11 | import fibre 12 | find_any = fibre.find_any 13 | find_all = fibre.find_all 14 | except: 15 | pass 16 | 17 | # Standard convention is to add a __version__ attribute to the package 18 | from .version import get_version_str 19 | __version__ = get_version_str() 20 | del get_version_str 21 | -------------------------------------------------------------------------------- /tools/odrive/code_generator.py: -------------------------------------------------------------------------------- 1 | 2 | import jinja2 3 | import os 4 | import json 5 | 6 | def get_flat_endpoint_list(json, prefix, id_offset): 7 | flat_list = [] 8 | for item in json: 9 | item = item.copy() 10 | if 'id' in item: 11 | item['id'] -= id_offset 12 | if 'type' in item: 13 | if item['type'] in {'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'}: 14 | item['type'] += '_t' 15 | is_property = True 16 | elif item['type'] in {'bool', 'float'}: 17 | is_property = True 18 | elif item['type'] in {'function'}: 19 | if len(item.get('arguments', [])) == 0 and len(item.get('inputs', [])) == 0 and len(item.get('outputs', [])) == 0: 20 | item['type'] = 'void' 21 | is_property = True 22 | else: 23 | is_property = False 24 | else: 25 | is_property = False 26 | if is_property: 27 | item['name'] = prefix + item['name'] 28 | flat_list.append(item) 29 | if 'members' in item: 30 | flat_list = flat_list + get_flat_endpoint_list(item['members'], prefix + item['name'] + '.', id_offset) 31 | return flat_list 32 | 33 | def generate_code(odrv, template_file, output_file): 34 | json_data = odrv._json_data 35 | json_crc = odrv._json_crc 36 | 37 | axis0_json = [item for item in json_data if item['name'].startswith("axis0")][0] 38 | axis1_json = [item for item in json_data if item['name'].startswith("axis1")][0] 39 | json_data = [item for item in json_data if not item['name'].startswith("axis")] 40 | endpoints = get_flat_endpoint_list(json_data, '', 0) 41 | per_axis_offset = axis1_json['members'][0]['id'] - axis0_json['members'][0]['id'] 42 | axis_endpoints = get_flat_endpoint_list(axis0_json['members'], 'axis.', 0) 43 | axis_endpoints_copy = get_flat_endpoint_list(axis1_json['members'], 'axis.', per_axis_offset) 44 | if axis_endpoints != axis_endpoints_copy: 45 | raise Exception("axis0 and axis1 don't look exactly equal") 46 | 47 | env = jinja2.Environment( 48 | #loader = jinja2.FileSystemLoader("/Data/Projects/") 49 | #trim_blocks=True, 50 | #lstrip_blocks=True 51 | ) 52 | 53 | # Expose helper functions to jinja template code 54 | #env.filters["delimit"] = camel_case_to_words 55 | 56 | #import ipdb; ipdb.set_trace() 57 | 58 | # Load and render template 59 | template = env.from_string(template_file.read()) 60 | output = template.render( 61 | json_crc=json_crc, 62 | endpoints=endpoints, 63 | per_axis_offset=per_axis_offset, 64 | axis_endpoints=axis_endpoints, 65 | output_name=os.path.basename(output_file.name) 66 | ) 67 | 68 | # Output 69 | output_file.write(output) 70 | -------------------------------------------------------------------------------- /tools/odrive/configuration.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import tempfile 4 | import odrive 5 | 6 | import fibre.remote_object 7 | from odrive.utils import OperationAbortedException, yes_no_prompt 8 | 9 | def get_dict(obj, is_config_object): 10 | result = {} 11 | for (k,v) in obj._remote_attributes.items(): 12 | if isinstance(v, fibre.remote_object.RemoteProperty) and is_config_object: 13 | result[k] = v.get_value() 14 | elif isinstance(v, fibre.remote_object.RemoteObject): 15 | sub_dict = get_dict(v, k == 'config') 16 | if sub_dict != {}: 17 | result[k] = sub_dict 18 | return result 19 | 20 | def set_dict(obj, path, config_dict): 21 | errors = [] 22 | for (k,v) in config_dict.items(): 23 | name = path + ("." if path != "" else "") + k 24 | if not k in obj._remote_attributes: 25 | errors.append("Could not restore {}: property not found on device".format(name)) 26 | continue 27 | remote_attribute = obj._remote_attributes[k] 28 | if isinstance(remote_attribute, fibre.remote_object.RemoteObject): 29 | errors += set_dict(remote_attribute, name, v) 30 | else: 31 | try: 32 | remote_attribute.set_value(v) 33 | except Exception as ex: 34 | errors.append("Could not restore {}: {}".format(name, str(ex))) 35 | return errors 36 | 37 | def get_temp_config_filename(device): 38 | serial_number = fibre.utils.get_serial_number_str(device) 39 | safe_serial_number = ''.join(filter(str.isalnum, serial_number)) 40 | return os.path.join(tempfile.gettempdir(), 'odrive-config-{}.json'.format(safe_serial_number)) 41 | 42 | def backup_config(device, filename, logger): 43 | """ 44 | Exports the configuration of an ODrive to a JSON file. 45 | If no file name is provided, the file is placed into a 46 | temporary directory. 47 | """ 48 | 49 | if filename is None: 50 | filename = get_temp_config_filename(device) 51 | 52 | logger.info("Saving configuration to {}...".format(filename)) 53 | 54 | if os.path.exists(filename): 55 | if not yes_no_prompt("The file {} already exists. Do you want to override it?".format(filename), True): 56 | raise OperationAbortedException() 57 | 58 | data = get_dict(device, False) 59 | with open(filename, 'w') as file: 60 | json.dump(data, file) 61 | logger.info("Configuration saved.") 62 | 63 | def restore_config(device, filename, logger): 64 | """ 65 | Restores the configuration stored in a file 66 | """ 67 | 68 | if filename is None: 69 | filename = get_temp_config_filename(device) 70 | 71 | with open(filename) as file: 72 | data = json.load(file) 73 | 74 | logger.info("Restoring configuration from {}...".format(filename)) 75 | errors = set_dict(device, "", data) 76 | 77 | for error in errors: 78 | logger.info(error) 79 | if errors: 80 | logger.warn("Some of the configuration could not be restored.") 81 | 82 | device.save_configuration() 83 | logger.info("Configuration restored.") 84 | -------------------------------------------------------------------------------- /tools/odrive/dfuse/COPYING: -------------------------------------------------------------------------------- 1 | 2 | The Python dfuse tool was written by Paul Liétar. 3 | Minor modifications were made for this project. 4 | Original source: https://github.com/plietar/dfuse-tool 5 | 6 | The license for this module is unclear. 7 | -------------------------------------------------------------------------------- /tools/odrive/dfuse/DfuFile.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | import struct 4 | import binascii 5 | 6 | def named(tuple,names): 7 | return dict(zip(names,tuple)) 8 | 9 | def parse(fmt,data,names): 10 | return named(struct.unpack(fmt,data),names) 11 | 12 | def fileunpack(f, fmt, names): 13 | n = struct.calcsize(fmt) 14 | return parse(fmt, f.read(n), names) 15 | 16 | class DfuFile: 17 | def __init__(self, path): 18 | self.targets = list() 19 | self.devInfo = dict() 20 | 21 | try: 22 | dfufile = open(path, 'rb') 23 | except: 24 | raise argparse.ArgumentTypeError('Could not open file %r' % path) 25 | 26 | with dfufile: 27 | 28 | header = fileunpack(dfufile, "<5sBLB", ('signature', 'version', 'size', 'targets')) 29 | 30 | if header['signature'] != b'DfuSe': 31 | raise argparse.ArgumentTypeError('File signature does not match') 32 | if header['version'] != 1: 33 | raise argparse.ArgumentTypeError('Unsupport DfuSe file version') 34 | 35 | for t in range(header['targets']): 36 | target_prefix = fileunpack(dfufile, "<6sBL255sLL", ('signature', 'alternate', 'named', 'name', 'size', 'elements')) 37 | if target_prefix['signature'] != b'Target': 38 | raise argparse.ArgumentTypeError('Target signature does not match') 39 | 40 | target = { 41 | 'name': target_prefix['name'].decode('ascii').rstrip('\0'), 42 | 'alternate': target_prefix['alternate'], 43 | 'elements': list() 44 | } 45 | 46 | for e in range(target_prefix['elements']): 47 | element_prefix = fileunpack(dfufile,"') 23 | else: 24 | print('Type "odrv0." and press ') 25 | print('This will present you with all the properties that you can reference') 26 | print('') 27 | print('For example: "odrv0.motor0.encoder.pos_estimate"') 28 | print('will print the current encoder position on motor 0') 29 | print('and "odrv0.motor0.pos_setpoint = 10000"') 30 | print('will send motor0 to 10000') 31 | print('') 32 | 33 | 34 | interactive_variables = {} 35 | 36 | discovered_devices = [] 37 | 38 | def did_discover_device(odrive, logger, app_shutdown_token): 39 | """ 40 | Handles the discovery of new devices by displaying a 41 | message and making the device available to the interactive 42 | console 43 | """ 44 | serial_number = odrive.serial_number if hasattr(odrive, 'serial_number') else "[unknown serial number]" 45 | if serial_number in discovered_devices: 46 | verb = "Reconnected" 47 | index = discovered_devices.index(serial_number) 48 | else: 49 | verb = "Connected" 50 | discovered_devices.append(serial_number) 51 | index = len(discovered_devices) - 1 52 | interactive_name = "odrv" + str(index) 53 | 54 | # Publish new ODrive to interactive console 55 | interactive_variables[interactive_name] = odrive 56 | globals()[interactive_name] = odrive # Add to globals so tab complete works 57 | logger.notify("{} to ODrive {:012X} as {}".format(verb, serial_number, interactive_name)) 58 | 59 | # Subscribe to disappearance of the device 60 | odrive.__channel__._channel_broken.subscribe(lambda: did_lose_device(interactive_name, logger, app_shutdown_token)) 61 | 62 | def did_lose_device(interactive_name, logger, app_shutdown_token): 63 | """ 64 | Handles the disappearance of a device by displaying 65 | a message. 66 | """ 67 | if not app_shutdown_token.is_set(): 68 | logger.warn("Oh no {} disappeared".format(interactive_name)) 69 | 70 | def launch_shell(args, logger, app_shutdown_token): 71 | """ 72 | Launches an interactive python or IPython command line 73 | interface. 74 | As ODrives are connected they are made available as 75 | "odrv0", "odrv1", ... 76 | """ 77 | 78 | interactive_variables = { 79 | 'start_liveplotter': start_liveplotter 80 | } 81 | 82 | # Expose all enums from odrive.enums 83 | interactive_variables.update({k: v for (k, v) in odrive.enums.__dict__.items() if not k.startswith("_")}) 84 | 85 | fibre.launch_shell(args, 86 | interactive_variables, 87 | print_banner, print_help, 88 | logger, app_shutdown_token, 89 | branding_short="odrv", branding_long="ODrive") 90 | -------------------------------------------------------------------------------- /tools/odrive/version.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import subprocess 4 | import os 5 | import sys 6 | 7 | def version_str_to_tuple(version_string): 8 | """ 9 | Converts a version string to a tuple of the form 10 | (major, minor, revision, prerelease) 11 | 12 | Example: "fw-v0.3.6-23" => (0, 3, 6, True) 13 | """ 14 | regex=r'.*v([0-9a-zA-Z]+).([0-9a-zA-Z]+).([0-9a-zA-Z]+)(.*)' 15 | return (int(re.sub(regex, r"\1", version_string)), 16 | int(re.sub(regex, r"\2", version_string)), 17 | int(re.sub(regex, r"\3", version_string)), 18 | (re.sub(regex, r"\4", version_string) != "")) 19 | 20 | 21 | def get_version_from_git(): 22 | script_dir = os.path.dirname(os.path.realpath(__file__)) 23 | try: 24 | # Determine the current git commit version 25 | git_tag = subprocess.check_output(["git", "describe", "--always", "--tags", "--dirty=*"], 26 | cwd=script_dir) 27 | git_tag = git_tag.decode(sys.stdout.encoding).rstrip('\n') 28 | 29 | (major, minor, revision, is_prerelease) = version_str_to_tuple(git_tag) 30 | 31 | # if is_prerelease: 32 | # revision += 1 33 | return git_tag, major, minor, revision, is_prerelease 34 | 35 | except Exception as ex: 36 | print(ex) 37 | return "[unknown version]", 0, 0, 0, 1 38 | 39 | def get_version_str(git_only=False, is_post_release=False, bump_rev=False): 40 | """ 41 | Returns the versions of the tools 42 | If git_only is true, the version.txt file is ignored even 43 | if it is present. 44 | """ 45 | script_dir = os.path.dirname(os.path.realpath(__file__)) 46 | 47 | # Try to read the version.txt file that is generated during 48 | # the packaging step 49 | version_file_path = os.path.join(script_dir, 'version.txt') 50 | if os.path.exists(version_file_path) and git_only == False: 51 | with open(version_file_path) as version_file: 52 | return version_file.readline().rstrip('\n') 53 | 54 | _, major, minor, revision, unreleased = get_version_from_git() 55 | if bump_rev: 56 | revision += 1 57 | version = '{}.{}.{}'.format(major, minor, revision) 58 | if is_post_release: 59 | version += ".post" 60 | elif unreleased: 61 | version += ".dev" 62 | return version 63 | 64 | if __name__ == '__main__': 65 | import argparse 66 | parser = argparse.ArgumentParser(description='Version Dump\n') 67 | parser.add_argument("--output", type=argparse.FileType('w'), default='-', 68 | help="C header output file") 69 | 70 | args = parser.parse_args() 71 | 72 | git_name, major, minor, revision, unreleased = get_version_from_git() 73 | args.output.write('#define FW_VERSION "{}"\n'.format(git_name)) 74 | args.output.write('#define FW_VERSION_MAJOR {}\n'.format(major)) 75 | args.output.write('#define FW_VERSION_MINOR {}\n'.format(minor)) 76 | args.output.write('#define FW_VERSION_REVISION {}\n'.format(revision)) 77 | args.output.write('#define FW_VERSION_UNRELEASED {}\n'.format(1 if unreleased else 0)) 78 | -------------------------------------------------------------------------------- /tools/odrive_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Example usage of the ODrive python library to monitor and control ODrive devices 4 | """ 5 | 6 | from __future__ import print_function 7 | 8 | import odrive 9 | import time 10 | import math 11 | 12 | # Find a connected ODrive (this will block until you connect one) 13 | my_drive = odrive.find_any() 14 | 15 | # Find an ODrive that is connected on the serial port /dev/ttyUSB0 16 | #my_drive = odrive.find_any("serial:/dev/ttyUSB0") 17 | 18 | # To read a value, simply read the property 19 | print("Bus voltage is " + str(my_drive.vbus_voltage) + "V") 20 | 21 | # Or to change a value, just assign to the property 22 | my_drive.axis0.controller.pos_setpoint = 3.14 23 | print("Position setpoint is " + str(my_drive.axis0.controller.pos_setpoint)) 24 | 25 | # And this is how function calls are done: 26 | my_drive.axis0.controller.set_pos_setpoint(0.0, 0.0, 0.0) 27 | 28 | # A sine wave to test 29 | t0 = time.monotonic() 30 | while True: 31 | setpoint = 10000.0 * math.sin((time.monotonic() - t0)*2) 32 | print("goto " + str(int(setpoint))) 33 | my_drive.axis0.controller.set_pos_setpoint(setpoint, 0.0, 0.0) 34 | time.sleep(0.01) 35 | 36 | 37 | # Some more things you can try: 38 | 39 | # Write to a read-only property: 40 | my_drive.vbus_voltage = 11.0 # fails with `AttributeError: can't set attribute` 41 | 42 | # Assign an incompatible value: 43 | my_drive.motor0.pos_setpoint = "I like trains" # fails with `ValueError: could not convert string to float` 44 | -------------------------------------------------------------------------------- /tools/odrive_header_template.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was autogenerated using the "odrivetool generate-code" feature. 3 | * 4 | * The file matches a specific firmware version. If you add/remove/rename any 5 | * properties exposed by the ODrive, this file needs to be regenerated, otherwise 6 | * the ODrive will ignore all commands. 7 | */ 8 | 9 | #ifndef __ODRIVE_ENDPOINTS_HPP 10 | #define __ODRIVE_ENDPOINTS_HPP 11 | {% macro enum_name(endpoint) %}{{ endpoint.name | replace('.', '__') | upper }}{% endmacro %} 12 | 13 | namespace odrive { 14 | 15 | static constexpr const uint16_t json_crc = 0x{{ "%0x" | format(json_crc) }}; 16 | 17 | static constexpr const uint16_t per_axis_offset = {{ per_axis_offset }}; 18 | 19 | enum { {% for endpoint in endpoints %} 20 | {{enum_name(endpoint)}} = {{endpoint.id}}, 21 | {%- endfor %} 22 | 23 | // Per-Axis endpoints (to be used with read_axis_property and write_axis_property) 24 | {%- for endpoint in axis_endpoints %} 25 | {{enum_name(endpoint)}} = {{endpoint.id}}, 26 | {%- endfor %} 27 | }; 28 | 29 | template 30 | struct endpoint_type; 31 | 32 | {% for endpoint in endpoints -%} 33 | template<> struct endpoint_type<{{enum_name(endpoint)}}> { typedef {{endpoint.type}} type; }; 34 | {% endfor %} 35 | 36 | // Per-axis endpoints 37 | {% for endpoint in axis_endpoints -%} 38 | template<> struct endpoint_type<{{enum_name(endpoint)}}> { typedef {{endpoint.type}} type; }; 39 | {% endfor %} 40 | 41 | template 42 | using endpoint_type_t = typename endpoint_type::type; 43 | 44 | } 45 | 46 | #endif // __ODRIVE_ENDPOINTS_HPP 47 | -------------------------------------------------------------------------------- /tools/odrivetool.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | ipython %~dp0\odrivetool -- %* 3 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | --index-url https://pypi.python.org/simple/ 2 | 3 | -e . -------------------------------------------------------------------------------- /tools/save_config_issue_example.py: -------------------------------------------------------------------------------- 1 | import odrive 2 | from fibre import Logger, Event 3 | from odrive.utils import OperationAbortedException 4 | from fibre.protocol import ChannelBrokenException 5 | 6 | def get_odrive(shutdown_token): 7 | print('Looking for ODrive...',end='') 8 | odrv = odrive.find_any(search_cancellation_token=app_shutdown_token, channel_termination_token=app_shutdown_token) 9 | print('Found.') 10 | return odrv 11 | 12 | def reboot_odrive(odrv): 13 | """ 14 | Reboot odrive 15 | """ 16 | try: 17 | odrv.reboot() 18 | except ChannelBrokenException: 19 | print('Lost connection because of reboot...') 20 | 21 | app_shutdown_token = Event() 22 | try: 23 | odrv0 = get_odrive(app_shutdown_token) 24 | print('Erasing configuration...',end='') 25 | odrv0.erase_configuration() 26 | print('Done.') 27 | reboot_odrive(odrv0) 28 | odrv0 = get_odrive(app_shutdown_token) 29 | 30 | print('*** Calling save_configuration() 3 times...',end='') 31 | odrv0.config.brake_resistance = 0.0 32 | odrv0.save_configuration() 33 | odrv0.config.brake_resistance = 1.0 34 | odrv0.save_configuration() 35 | odrv0.config.brake_resistance = 2.0 36 | odrv0.save_configuration() 37 | odrv0.config.brake_resistance = 3.0 38 | odrv0.save_configuration() 39 | print('Done.') 40 | 41 | reboot_odrive(odrv0) 42 | 43 | odrv0 = get_odrive(app_shutdown_token) 44 | print('Brake resistance (should be 2.0): ',end='') 45 | print(odrv0.config.brake_resistance) 46 | 47 | # init_odrive(odrv0) 48 | except OperationAbortedException: 49 | logger.info("Operation aborted.") 50 | finally: 51 | app_shutdown_token.set() 52 | -------------------------------------------------------------------------------- /tools/test-rig-loopback.yaml: -------------------------------------------------------------------------------- 1 | 2 | type: loopback 3 | 4 | odrives: 5 | - name: odrv-blackside 6 | board-version: v3.4-24V 7 | serial-number: "3061395B3235" 8 | brake-resistance: 0.47 9 | uart: /dev/serial/by-id/[not-yet-used] 10 | usb: auto 11 | programmer: '\x49\x3f\x6f\x06\x49\x3f\x56\x54\x09\x29\x11\x3f' 12 | vbus-voltage: 24 # [V] 13 | max-brake-power: 150 # [W] 14 | axes: 15 | - name: 'M0' 16 | motor-phase-resistance: 0.028 17 | motor-phase-inductance: 1.6e-05 18 | motor-pole-pairs: 7 19 | motor-direction: 1 20 | motor-kv: 270 21 | motor-max-current: 70 22 | motor-max-voltage: 32 23 | encoder-cpr: 8192 24 | encoder-max-rpm: 7000 25 | - name: 'M1' 26 | motor-phase-resistance: 0.028 27 | motor-phase-inductance: 1.6e-05 28 | motor-pole-pairs: 7 29 | motor-direction: -1 30 | motor-kv: 270 31 | motor-max-current: 70 32 | motor-max-voltage: 32 33 | encoder-cpr: 8192 34 | encoder-max-rpm: 7000 35 | - name: odrv-yellowside 36 | board-version: v3.5-48V 37 | serial-number: "3660335E3037" 38 | brake-resistance: 0.47 39 | uart: /dev/serial/by-id/[not-yet-used] 40 | usb: auto 41 | programmer: '\x53\x3f\x75\x06\x49\x3f\x49\x51\x44\x54\x19\x3f' 42 | vbus-voltage: 48 # [V] 43 | max-brake-power: 150 # [W] 44 | axes: 45 | - name: 'M0' 46 | motor-phase-resistance: 0.0245 47 | motor-phase-inductance: 2.03e-05 48 | motor-pole-pairs: 7 49 | motor-direction: 1 50 | motor-kv: 190 51 | motor-max-current: 70 52 | motor-max-voltage: 40 53 | encoder-cpr: 8192 54 | encoder-max-rpm: 7000 55 | - name: 'M1' 56 | motor-phase-resistance: 0.0245 57 | motor-phase-inductance: 2.03e-05 58 | motor-pole-pairs: 7 59 | motor-direction: -1 60 | motor-kv: 190 61 | motor-max-current: 70 62 | motor-max-voltage: 40 63 | encoder-cpr: 8192 64 | encoder-max-rpm: 7000 65 | 66 | # Mechanical couplings 67 | couplings: 68 | - [ odrv-blackside.M0, odrv-blackside.M1 ] 69 | - [ odrv-yellowside.M0, odrv-yellowside.M1 ] -------------------------------------------------------------------------------- /tools/test-rig-parallel.yaml: -------------------------------------------------------------------------------- 1 | 2 | type: parallel 3 | 4 | # ODrives 5 | odrives: 6 | - name: top-odrive 7 | board-version: v3.5-48V 8 | serial-number: "3660335E3037" 9 | brake-resistance: 0.47 10 | uart: /dev/serial/by-id/[not-yet-used] 11 | usb: auto 12 | programmer: '\x53\x3f\x75\x06\x49\x3f\x49\x51\x44\x54\x19\x3f' 13 | vbus-voltage: 24 # [V] 14 | max-brake-power: 150 # [W] 15 | axes: 16 | - name: 'yellow' 17 | motor-phase-resistance: 0.0245 18 | motor-phase-inductance: 2.03e-05 19 | motor-pole-pairs: 7 20 | motor-direction: 1 21 | motor-kv: 190 22 | motor-max-current: 70 23 | motor-max-voltage: 40 24 | encoder-cpr: 8192 25 | encoder-max-rpm: 7000 26 | - name: 'black' 27 | motor-phase-resistance: 0.028 28 | motor-phase-inductance: 1.6e-05 29 | motor-pole-pairs: 7 30 | motor-direction: -1 31 | motor-kv: 270 32 | motor-max-current: 70 33 | motor-max-voltage: 32 34 | encoder-cpr: 8192 35 | encoder-max-rpm: 7000 36 | - name: bottom-odrive 37 | board-version: v3.5-24V 38 | serial-number: "3661335E3037" 39 | brake-resistance: 0.47 40 | uart: /dev/serial/by-id/[not-yet-used] 41 | usb: auto 42 | programmer: '\x49\x3f\x6f\x06\x49\x3f\x56\x54\x09\x29\x11\x3f' 43 | vbus-voltage: 24 # [V] 44 | max-brake-power: 150 # [W] 45 | axes: 46 | - name: 'black' 47 | motor-phase-resistance: 0.028 48 | motor-phase-inductance: 1.6e-05 49 | motor-pole-pairs: 7 50 | motor-direction: 1 51 | motor-kv: 270 52 | motor-max-current: 70 53 | motor-max-voltage: 32 54 | encoder-cpr: 8192 55 | encoder-max-rpm: 7000 56 | - name: 'yellow' 57 | motor-phase-resistance: 0.0245 58 | motor-phase-inductance: 2.03e-05 59 | motor-pole-pairs: 7 60 | motor-direction: -1 61 | motor-kv: 190 62 | motor-max-current: 70 63 | motor-max-voltage: 40 64 | encoder-cpr: 8192 65 | encoder-max-rpm: 7000 66 | 67 | # Mechanical couplings 68 | couplings: 69 | - [ top-odrive.yellow, bottom-odrive.yellow ] 70 | - [ top-odrive.black, bottom-odrive.black ] 71 | -------------------------------------------------------------------------------- /tools/usbpermission: -------------------------------------------------------------------------------- 1 | sudo udevadm control --reload-rules && sudo service udev restart && sudo udevadm trigger 2 | --------------------------------------------------------------------------------