various documentation updates

This commit is contained in:
Samuel Sadok
2018-04-14 15:44:51 -07:00
parent f258211952
commit 58d1cacf3b
10 changed files with 129 additions and 205 deletions
+2 -2
View File
@@ -5,8 +5,8 @@
sections:
- title: For Users
docs:
- title: Quick Start Guide
url: quick-start
- title: Getting Started
url: getting-started
- title: ODrive Tool
url: odrivetool
- title: Parameters & Commands
+4 -2
View File
@@ -379,11 +379,13 @@ details > div > p:last-child {
color: black;
background-color: #ffc40096;
margin-bottom: 15px;
//border: solid 1px #000000;
}
.alert * {
.note {
padding: 10px;
color: black;
background-color: #0099ff44;
margin-bottom: 15px;
}
/*** inline code ***/
+18 -19
View File
@@ -2,21 +2,6 @@
We will use the `<odrv>` as a placeholder for any ODrive object. In `odrivetool` this is usually `odrv0`. Furthermore we use `<axis>` as a placeholder for any axis (for example `odrv0.axis0`).
## General system commands
### Saving the configuration
All variables that are part of a `[...].config` object can be saved to non-volatile memory on the ODrive so they persist after you remove power. The relevant commands are:
* `<odrv>.save_configuration()`: Stores the configuration to persistent memory on the ODrive.
* `<odrv>.erase_configuration()`: Resets the configuration variables to their factory defaults. This only has an effect after a reboot. A side effect of this command is that motor control stops (in case it was running) and the USB communication breaks out temporarily. This is because erasing flash pages hangs the microcontroller for several seconds.
### Diagnostics
* `<odrv>.serial_number`: A number that uniquely identifies your device. When printed in upper case hexadecimal (`hex(<odrv>.serial_number).upper()`), this is identical to the serial number indicated by the USB descriptor.
* `<odrv>.fw_version_major`, `<odrv>.fw_version_minor`, `<odrv>.fw_version_revision`: The firmware version that is currently running.
* `<odrv>.hw_version_major`, `<odrv>.hw_version_minor`, `<odrv>.hw_version_revision`: The hardware version of your ODrive.
## Per-Axis commands
For the most part, both axes on the ODrive can be controlled independently.
@@ -56,16 +41,14 @@ This behavior can be changed by modifying the following parameters:
See [state machine](#state-machine) for a description of each state.
### Control Mode
By default both motors are enabled, and the default control mode is position control.
If you want a different mode, you can change `odrv0.motorN.config.control_mode`.
The default control mode is position control.
If you want a different mode, you can change `<axis>.controller.config.control_mode`.
Possible values are:
* `CTRL_MODE_POSITION_CONTROL`
* `CTRL_MODE_VELOCITY_CONTROL`
* `CTRL_MODE_CURRENT_CONTROL`
* `CTRL_MODE_VOLTAGE_CONTROL` - this one is not normally used.
To disable a motor at startup, set `odrv0.axisN.config.enable_control` and `odrv0.axisN.config.do_calibration` to `False`.
### Tuning parameters
The motion control gains are currently manually tuned:
* `odrv0.motorN.config.pos_gain = 20.0f` [(counts/s) / counts]
@@ -80,3 +63,19 @@ An upcoming feature will enable automatic tuning. Until then, here is a rough tu
* Increase `pos_gain` by around 30% per iteration until you see some overshoot.
* Back down `pos_gain` until you do not have overshoot anymore.
* The integrator is not easily tuned, nor is it strictly required. Tune at your own discression.
## General system commands
### Saving the configuration
All variables that are part of a `[...].config` object can be saved to non-volatile memory on the ODrive so they persist after you remove power. The relevant commands are:
* `<odrv>.save_configuration()`: Stores the configuration to persistent memory on the ODrive.
* `<odrv>.erase_configuration()`: Resets the configuration variables to their factory defaults. This only has an effect after a reboot. A side effect of this command is that motor control stops (in case it was running) and the USB communication breaks out temporarily. This is because erasing flash pages hangs the microcontroller for several seconds.
### Diagnostics
* `<odrv>.serial_number`: A number that uniquely identifies your device. When printed in upper case hexadecimal (`hex(<odrv>.serial_number).upper()`), this is identical to the serial number indicated by the USB descriptor.
* `<odrv>.fw_version_major`, `<odrv>.fw_version_minor`, `<odrv>.fw_version_revision`: The firmware version that is currently running.
* `<odrv>.hw_version_major`, `<odrv>.hw_version_minor`, `<odrv>.hw_version_revision`: The hardware version of your ODrive.
+1 -1
View File
@@ -33,7 +33,7 @@ A terminal window will open with your native shell. VSCode is configured to run
A terminal window will open with your native shell. VSCode is configured to run the command `make flash` in this terminal.
If the flashing worked, you can connect to the board using the [odrivetool](../docs/quick-start#start-odrivetool).
If the flashing worked, you can connect to the board using the [odrivetool](../docs/getting-started#start-odrivetool).
## Debugging
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
+1 -1
View File
@@ -114,7 +114,7 @@ You can also modify the compile-time defaults for all `.config` parameters. You
* You need to power the board by only **ONE** of the following: VCC(3.3v), 5V, or the main power connection (the DC bus). The USB port (J1) does not power the board.
* Run `make flash` in the `Firmware` directory.
If the flashing worked, you can connect to the board using the [odrivetool](quick-start#start-odrivetool).
If the flashing worked, you can connect to the board using the [odrivetool](getting-started#start-odrivetool).
<br><br>
## Debugging
+2 -2
View File
@@ -19,7 +19,7 @@ If you have a choice, this is the recommended protocol for all applications.
### Python
The ODrive tools you installed earlier come with a library that you can use to easily control the ODrive from Python.
The ODrive Tool you installed as part of the [Getting Started guide](getting-started#downloading-and-installing-tools) comes with a library that you can use to easily control the ODrive from Python.
Assuming you already installed the odrive library (`pip install odrive`), the simplest program to control the ODrive is this:
@@ -29,7 +29,7 @@ odrv0 = odrive.discovery.find_any()
print(str(odrv0.vbus_voltage))
```
For a more detailed example, see [odrive_demo.py](../tools/odrive_demo.py).
For a more comprehensive example, see [odrive_demo.py](../tools/odrive_demo.py).
### Other languages
+100 -8
View File
@@ -1,23 +1,115 @@
# ODrive Tool
### Multiple ODrives
The ODrive Tool is the accompanying PC program for the ODrive. It's main purpose is to provide an interactive shell to control the device manually, as well as some supporting functions like firmware update.
## Installation
Refer to the [Getting Started guide](getting-started#downloading-and-installing-tools).
Type `odrivetool --help` to see what features are available.
## Multiple ODrives
By default, `odrivetool` will connect to any ODrive it finds. If this is not what you want, you can select a specific ODrive.
If you have multiple ODrives connected, you should specify which one to connect to.
* Run `(lsusb -d 1209:0d32 -v; lsusb -d 0483:df11 -v) 2>/dev/null | grep iSerial` to list the serial number of all flashable devices. Example output:
To find the serial number of your ODrive, run `odrivetool`, connect exactly one ODrive and power it up. You should see this:
```
Connected to ODrive 306A396A3235 as odrv0
In [1]:
```
`306A396A3235` is the serial number of this particular ODrive. If you want ODrive Tool to ignore all other devices you would close it and then run `odrivetool --serial-number 306A396A3235`.
<details><summary markdown="span">My ODrive is stuck in DFU mode, can I still find the serial number?</summary><div markdown="block">
Yes, the serial number is part of the USB descriptors.
In Linux you can find it by running:
```
$ (sudo lsusb -d 1209:0d32 -v; sudo lsusb -d 0483:df11 -v) 2>/dev/null | grep iSerial
iSerial 3 385F324D3037
iSerial 3 306A396A3235
```
* The last column is the serial number you're looking for. You can unplug selected devices to track down the one you want to update.
* Run `odrivetool --serial-number=385F324D3037`, where `385F324D3037` is the targeted serial number.
* To connect over serial, run `odrivetool --path serial`.
Here, two ODrives are connected.
</div></details>
## Device Firmware Update
Note: ODrive v3.4 and earlier require you to flash with the external programmer first (see below), before you can reflash in standalone mode.
<div class="note" markdown="span">__ODrive v3.3, v3.4__: You need to flash with the external programmer first (see [below](#flashing-with-an-stlink)), before you can reflash in DFU mode.</div>
1. Download the latest firmware release form [here](https://github.com/madcowswe/ODrive/releases). You will need the __.hex__ file. Make sure you select the file that matches your board version.
2. Open up a terminal and navigate to the directory where the firmware is.
3. Run the following command (replace `ODriveFirmware_v3.4-24V.hex` with the name of your firmware file):
```
~/Downloads $ odrivetool dfu ODriveFirmware_v3.4-24V.hex
ODrive control utility v0.3.7.dev-11
Waiting for ODrive...
Putting device 306A396A3235 into DFU mode...
Found device 306A396A3235 in DFU mode
Erasing... done
Flashing... done
Verifying... done
```
### Troubleshooting
* Run `make dfu` in the `Firmware` directory.
* __Windows__: During the update, a new device called "STM32 BOOTLOADER" will appear. Open the [Zadig utility](http://zadig.akeo.ie/) and set the driver for "STM32 BOOTLOADER" to libusb-win32. After that the firmware update will continue.
* On some machines you will need to unplug and plug back in the USB cable to make the PC understand that we switched from regular mode to bootloader mode.
* Currently a firmware update will preserve the configuration if and only if the parameters of both firmware versions are identical. This will change in the future.
* If the DFU script can't find the device, try forcing it into DFU mode.
<details><summary markdown="span">How to force DFU mode (ODrive v3.5)</summary><div markdown="block">
Flick the DIP switch that "DFU, RUN" to "DFU" and power cycle the board. If that alone doesn't work, also connect the After you're done, put the switch back into the "RUN" position and power cycle the board again.
</div></details>
<details><summary markdown="span">How to force DFU mode (ODrive v3.1, v3.2)</summary><div markdown="block">
Connect the pin "BOOT0" to "3.3V" and power cycle the board. If that alone doesn't work, also connect the pin "GPIO1" to "GND". After you're done, remove the wires and power cycle the board again.
</div></details>
## Flashing with an STLink
This procedure is only necessary for ODrive v3.4. You will need an STLink/v2 or compatible programmer. You should have received one with your ODrive.
1. Install OpenOCD
* **Windows:** [instructions](http://gnuarmeclipse.github.io/openocd/install/) (also follow the instructions on the ST-LINK/V2 drivers)
* **Linux:** `sudo apt-get install openocd`
* **macOS:** `brew install openocd`
2. Download the latest firmware release form [here](https://github.com/madcowswe/ODrive/releases). You will need the __.elf__ file. Make sure you select the file that matches your board version.
3. Wire up the ODrive and STLink/v2 programmer as shown in this picture:<br>
![stlink-wiring](stlink-wiring-cropped.jpg)
Power up the ODrive.
4. Open up a terminal and navigate to the directory where the firmware is.
5. Run the following command (replace `ODriveFirmware_v3.4-24V.elf` with the name of your firmware file):
```
~/Downloads $ openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c init -c reset\ halt -c flash\ write_image\ erase\ ODriveFirmware_v3.4-24V.elf -c reset\ run -c exit
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 2000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : clock speed 1800 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.236027
Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
adapter speed: 2000 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08009224 msp: 0x20020000
auto erase enabled
Info : device id = 0x10076413
Info : flash size = 1024kbytes
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x20000046 msp: 0x20020000
Warn : no flash bank found for address 10000000
wrote 262144 bytes from file ODriveFirmware_v3.4-24V.elf in 10.194110s (25.113 KiB/s)
adapter speed: 2000 kHz
```
From now on you can use the device with the DFU feature. If you modify the firmware in a way that prevents it from communicating, you may have to repeat this procedure.
If something doesn't work, make sure `openocd` is in your `PATH` variable, check that the wires are connected properly and try with elevated privileges.
-169
View File
@@ -1,169 +0,0 @@
# Quick Start Guide
### Table of contents
<!-- MarkdownTOC depth=2 autolink=true bracket=round -->
- [Wiring up the ODrive](#wiring-up-the-odrive)
- [Downloading and Installing Tools](#downloading-and-installing-tools)
- [Start `odrivetool`](#start-odrivetool)
- [Configure M0](#configure-m0)
- [Position control of M0](#position-control-of-m0)
- [What's next?](#whats-next)
<!-- /MarkdownTOC -->
## Wiring up the ODrive
<div class="alert">
Make sure you have a good mechanical connection between the encoder and the motor, slip can cause disasterous oscillations.
</div>
All non-power I/O is 3.3V output and 5V tolerant on input, except:
<div class="alert" markdown="span"> __ODrive v3.2__: GPIO 3 and GPIO 4 are __not__ 5V tolerant.</div>
You will need:
* One or two [brushless motors](https://hackaday.io/project/11583-odrive-high-performance-motor-control/log/37666-hobby-motors-in-your-robots). It is fine, even recommended, to start testing with just a single motor and encoder.
* One or two [quadrature incremental encoder(s)](https://discourse.odriverobotics.com/t/which-encoders-to-choose/63/2)
* A power resistor. A good starting point would be a [0.47 ohm, 50W resistor](https://www.digikey.com/product-detail/en/te-connectivity-passive-product/HSA50R47J/A102181-ND/2056131)
<details><summary markdown="span">Do I really need a power resistor? What values to choose?</summary><div markdown="block">
If you don't have a brake resistor, the ODrive will pump excess power back into the power supply during deceleration to achieve the desired deceleration torque. If your power supply doesn't eat that power (which it won't if it's not a battery), the bus voltage will inevitebly rise. If you're unlucky this will break the power supply.
At some point, the ODrive's overvoltage protection will trip, after which both motors will be allowed to spin freely. Depending on your machine, this may or may not be a problem.
The power resistor values you need depends on your motor setup, and peak/average deceleration power.
To be on the safe side, think about what speed and current limits you want to set for the motor.
When braking at max speed and with maximum motor current, the power that is dissipated in the power resistor can be calulated as: `P_brake = V_emf * I_motor` where `V_emf = motor_kv * V_bus`.
</div></details>
* A power supply (12V-24V for the 24V board variant, 12V-48V for the 48V board variant). A battery is also fine.
1. Wire up the motor phases into the 3-phase screw terminals, and the power resistor to the AUX terminal. Wire up the power source to the DC terminal, make sure to pay attention to the polarity. Do not apply power just yet.
2. Wire up the encoder(s) to J4. The A,B phases are required, and the Z (index pulse) is optional. The A,B and Z lines have 3.3k pull up resistors, for use with open-drain encoder outputs. For single ended push-pull signals with weak drive current (\<4mA), you may want to desolder the pull-ups.
![Image of ODrive all hooked up](https://docs.google.com/drawings/d/e/2PACX-1vTCD0P40Cd-wvD7Fl8UYEaxp3_UL81oI4qUVqrrCJPi6tkJeSs2rsffIXQRpdu6rNZs6-2mRKKYtILG/pub?w=1716&h=1281)
## Downloading and Installing Tools
Most instructions in this guide refer to a utility called `odrivetool`, so you should install that first.
### Windows
1. Install Python 3. We recommend the Anaconda distribution because it packs a lot of useful scientific tools, however you can also install the standalone python.
* __Anaconda__: Download the installer from [here](https://www.anaconda.com/download/#windows). Execute the downloaded file and follow the instructions.
* __Standalone Python__: Download the installer from [here](https://www.python.org/downloads/). Execute the downloaded file and follow the instructions.
* If you have Python 2 installed alongside Python 3, replace `pip` by `C:\Users\YOUR_USERNAME\AppData\Local\Programs\Python\Python36-32\Scripts\pip`. If you have trouble with this step then refer to [this walkthrough](https://www.youtube.com/watch?v=jnpC_Ib_lbc).
2. Launch the command prompt.
* __Anaconda__: In the start menu, type `Anaconda Prompt` <kbd>Enter</kbd>
* __Standalone Python__: In the start menu, type `cmd` <kbd>Enter</kbd>
3. Install the ODrive tools by typing `pip install odrive` <kbd>Enter</kbd>
4. Plug in a USB cable into the microUSB connector on ODrive, and connect it to your PC.
5. Use the [Zadig](http://zadig.akeo.ie/) utility to set ODrive driver to libusb-win32.
* If 'Odrive version 3.x' is not in the list of devices upon opening Zadig, check 'List All Devices' from the options menu. With the Odrive selected in the device list choose 'libusb-win32' from the target driver list and select the large 'install driver' button.
### Linux/macOS
1. [Install Python 3](https://www.python.org/downloads/).
2. Install the ODrive tools by opening a terminal and typing `pip install odrive` <kbd>Enter</kbd>
3. __Linux__: set up USB permissions
```bash
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="0d[0-9][0-9]", MODE="0666"' | sudo tee /etc/udev/rules.d/50-odrive.rules
sudo udevadm control --reload-rules
sudo udevadm trigger # until you reboot you may need to do this everytime you reset the ODrive
```
## Start `odrivetool`
To launch the main interactive ODrive tool, type `odrivetool` <kbd>Enter</kbd>. Connect your ODrive and wait for the tool to find it. Now you can for instance type `odrv0.vbus_voltage` <kbd>Enter</kbd> to inpect the boards main supply voltage.
It should look something like this:
```python
ODrive control utility v0.4.0
Please connect your ODrive.
Type help() for help.
Connected to ODrive 306A396A3235 as odrv0
In [1]: odrv0.vbus_voltage
Out[1]: 11.97055721282959
```
The tool you're looking at is a fully capable Python command prompt, so you can type any valid python code.
## Configure M0
<div class="alert">Read this section carefully, else you risk breaking something.</div>
1. Set the limits:
<details><summary markdown="span">Wait, how do I set these?</summary><div markdown="block">
In the previous step we started `odrivetool`. In there, you can assign variables directly by name.
For instance, to set the current limit of M0 to 10A you would type: `odrv0.axis0.motor.config.current_lim = 10` <kbd>Enter</kbd>
</div></details>
* The current limit: `odrv0.axis0.motor.config.current_lim` [A]. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you can increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains.
* Note: The motor current and the current drawn from the power supply is not the same in general. You should not look at the power supply current to see what is going on with the motor current.
* The velocity limit: `odrv0.axis0.motor.config.vel_limit` [counts/s]. The motor will be limited to this speed; again the default value is quite slow.
* You can change `odrv0.axis0.motor.config.calibration_current` [A] to the largest value you feel comfortable leaving running through the motor continously when the motor is stationary.
2. Set other hardware parameters:
* `odrv0.config.brake_resistance` [Ohm]: This is the resistance of the brake resistor. If you are not using it, you may set it to `0`.
* `odrv0.axis0.motor.config.pole_pairs`: This is the number of **magnet poles** in the rotor, **divided by two**. You can simply count the number of permanent magnets in the rotor, if you can see them. _Note: this is not the same as the number of coils in the stator._
* `odrv0.axis0.motor.config.motor_type`: This is the type of motor being used. Currently two types of motors are supported: High-current motors (`MOTOR_TYPE_HIGH_CURRENT`) and Gimbal motors (`MOTOR_TYPE_GIMBAL`).
<details><summary markdown="span">Which `motor_type` to choose?</summary><div markdown="block">
If you're using a regular hobby brushless motor like [this](https://hobbyking.com/en_us/turnigy-aerodrive-sk3-5065-236kv-brushless-outrunner-motor.html) one, you should set `motor_mode` to `MOTOR_TYPE_HIGH_CURRENT`. For low-current gimbal motors like [this](https://hobbyking.com/en_us/turnigy-hd-5208-brushless-gimbal-motor-bldc.html) one, you should choose `MOTOR_TYPE_GIMBAL`. Do not use `MOTOR_TYPE_GIMBAL` on a motor that is not a gimbal motor, as it may overheat the motor or the ODrive.
**Further detail:**
If 100's of mA of current noise is "small" for you, you can choose `MOTOR_TYPE_HIGH_CURRENT`.
If 100's of mA of current noise is "large" for you, and you do not intend to spin the motor very fast (omega * L << R), and the motor is fairly large resistance (1 ohm or larger), you can chose `MOTOR_TYPE_GIMBAL`.
If 100's of mA current noise is "large" for you, _and_ you intend to spin the motor fast, then you need to replace the shunt resistors on the ODrive.
</div></details>
* `odrv0.axis0.encoder.config.cpr`: Encoder Count Per Revolution (CPR). This is 4x the Pulse Per Revolution (PPR) value. Usually this is indicated in the datasheet of your encoder.
## Position control of M0
Let's get motor 0 up and running. The procedure for motor 1 is exactly the same, so feel free to replace read "axis1" wherever it says "axis0".
1. Type `odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE` <kbd>Enter</kbd>. After about 2 seconds should hear a beep. Then the motor will turn slowly in one direction for a few seconds, then back in the other direction.
<details><summary markdown="span">What's the point of this?</summary><div markdown="block">
This procedure first measures your motor's electrical properties (namely phase resistance and phase inductance) and then the offset between the motor's electrical phase and the encoder position.
</div></details>
The startup procedure is demonstrated [here](https://www.youtube.com/watch?v=VCX1bA2xnuY).
Note: 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. Also note that in the video, the motors spin after initalisation, but in the current software the default behaviour is to do position control to position 0 (i.e. the position at startup)
<details><summary markdown="span">My motor doesn't beep or doesn't turn</summary><div markdown="block">
Make sure the motor wires are connected firmly. Check the value of `odrv0.axis0.error` and then refer to the [error code documentation](troubleshooting.md#error-codes) for details.
Once you have understood the error and fixed its cause, you may clear the error state (`odrv0.axis0.error = 0` <kbd>Enter</kbd>) and retry. You may also need to clear the error state of other subcomponents (e.g. `odrv0.axis0.motor.error`).
</div></details>
3. Type `odrv0.axis0.motor.config.pre_calibrated = True` <kbd>Enter</kbd> and then `odrv0.save_configuration()` <kbd>Enter</kbd>. This will save all the configuration and calibration you just did so the next time you start the device it's already ready to go. Except for one thing: you need to run the encoder offset calibration after every power cycle.
4. Type `odrv0.axis0.requested_state = AXIS_STATE_CLOSED_CONTROL_LOOP` <kbd>Enter</kbd>. From now on the ODrive will try to hold the motor's position. If you try to turn it by hand, it will fight you gently. That is unless you bump up `odrv0.axis0.motor.config.current_lim`, in which case it will fight you more fiercely.
## What's next?
You can now:
* Set the [tuning parameters](commands#tuning-parameters) for better performance
* Control the ODrive from your own program or hook it up to an existing system through one of it's [interfaces](interfaces)
If you have any issues or any questions please get in touch. The [ODrive Community](https://discourse.odriverobotics.com/) warmly welcomes you.
Binary file not shown.

After

Width:  |  Height:  |  Size: 997 KiB

+1 -1
View File
@@ -82,7 +82,7 @@ fault detection.
* Try turning it on and off again (the ODrive, the script, the PC)
* Make sure you're using the latest firmware and python tools release
* **Linux**: Type `lsusb` to list all USB devices. Verify that your ODrive is listed.
* **Linux**: Make sure you [set up your udev rules](quick-start#downloading-and-installing-tools) correctly.
* **Linux**: Make sure you [set up your udev rules](getting-started#downloading-and-installing-tools) correctly.
* **Windows**: Right-click on the start menu and open "Device Manager". Verify that your ODrive is listed.
* **Windows**: Use the [Zadig utility](http://zadig.akeo.ie/) to verify the driver is
* Ensure that no other ODrive program is running