ebelski / rust-copter

A quadcopter build using a Teensy running Rust and some other cool stuff that's yet to be determined.
MIT License
6 stars 1 forks source link

Integrate IMU reading into pwm-control demo #29

Closed mciantyre closed 4 years ago

mciantyre commented 4 years ago

The PR adds optional IMU streaming in the existing pwm-control example. If you connect an MPU9250 to the Teensy (I2C) and flash the pwm-control example, the Teensy reads the IMU at 100Hz. It serializes the readings, and writes them over UART. The readings are binary encoded, requiring a deserialization step to turn them into something useful. You can deserialize the readings on the host using Python and the pymotion-sensor library. To see the readings in real-time, use the imu-parse.py script.

With this new feature, we can use one demo to both control motors and also stream IMU measurements from the Teensy. This should close #18. We also have a Python interface to stream and deserialize IMU measurements. With this, and a separate Python interface to send motor commands, we can implement low-speed control on our computers in Python (or any other language). Once we have a POC, we can migrate it to the embedded system.

The table below provides the additional pinout for the pwm-control example. The table is also in the pwm-control docs.

Teensy 4 Pin Teensy 4 Function Connection
14 UART2 TX Host UART RX
15 UART2 RX Host UART TX
16 I2C3 SCL MPU SCL
17 I2C3 SDA MPU SDA

Note that the IMU and UART connections are optional. If you don't connect the IMU, the example still lets you control motors. Also note that the IMU data path is UART, not the USB serial interface. It was easier to keep the IMU data and motor control paths on separate peripherals. This requires a separate connection to the Teensy; use the cable acquired in #9.

See the tools/README.md documentation for instructions on installing and testing the Python tools.

ebelski commented 4 years ago

@mciantyre I'm waiting on the FTDI cable before I can review this.

ebelski commented 4 years ago

The cable has arrived and I anticipate taking care of this next week sometime.

ebelski commented 4 years ago

@mciantyre , why did you merge the master branch into the demo/imu-pwm branch? It doesn't matter to me but I'm assuming there's some reason why that was the workflow and I'd like to better understand.

ebelski commented 4 years ago

Also, I merged it back into the master branch but I'd like to keep this node just in case we need to roll back while I'm doing my testing.

mciantyre commented 4 years ago

why did you merge the master branch into the demo/imu-pwm branch?

This branch (demo/imu-pwm) co-existed with #30's branch (update-deps). demo/imu-pwm was incompatible with update-deps. After we merged #30, this PR became incompatible with master, because master included update-deps.

A history-preserving fix is to merge master into this branch, and fix the merge conflicts in one commit: 7cc25c93. This acquires the incompatibilities, and fixes the issues, so we can merge this branch.

ebelski commented 3 years ago

The table below provides the additional pinout for the pwm-control example. The table is also in the pwm-control docs.

Teensy 4 Pin Teensy 4 Function Connection 14 UART2 TX Host UART RX 15 UART2 RX Host UART TX 16 I2C3 SCL MPU SCL 17 I2C3 SDA MPU SDA

Is it intentional that 14 UART2 TX points to Host UART RX? And that 15UART2 RX points to Host UART TX? I'm having difficulty getting output on my ftdi cable through the imu-parse.py script. The com port opens and doesn't display any text.

ebelski commented 3 years ago

@mciantyre , could you put together a brief guide for me to test the reading in of the imu over the ftdi cable while controlling the motors? Just to make sure I'm using the right version of the hex scripts, python scripts, and cable connections.

mciantyre commented 3 years ago

Is it intentional that 14 UART2 TX points to Host UART RX? And that 15UART2 RX points to Host UART TX?

This is intentional. Imagine holding two phones together to connect a call. To do it correctly, you hold the speaker (output, TX) of one phone to the microphone (input, RX) on the other phone. Same applies for these serial connections.

Let's give it a go. Use whatever is on master right now: git checkout master. (a0c5cda as of this writing.)

MPU to Teensy 4

Since it's a simpler demo, let's use the mpu9250-i2c example to make sure your MPU9250 is correctly connected to the Teensy 4. Build and flash the example:

./task.py demo mpu9250-i2c

This generates the output target/thumbv7em-none-eabihf/release/demo-mpu9250-i2c.hex. Flash that output to your board.

Open a serial connection to the Teensy 4's USB output. Use PuTTY on Windows, or screen on *nix. Baud rate doesn't matter. About 20 seconds after flashing the mpu9250-i2c demo, you should see 9DOF readings appear at 4Hz. If you do not see these readings, it's likely that your connections to the MPU9250 are incorrect. See the connection instructions here. Make sure that the sensor is powered. If the issue persists, try to power-cycle the entire system; the MPU might be stuck in a strange state.

If you see 9DOF readings at 4Hz, your connections to the MPU9250 and Teensy 4 are correct. Let's check the FTDI to Teensy 4 connection. Keep the MPU connected to your board.

FTDI to Teensy 4

test-ftdi.hex.zip

Download the above ZIP file. Unzip it to find test-ftdi.hex, and flash that HEX file to your Teensy 4. You should see the LED blinking. Connect your FTDI cable to the Teensy 4 as described in the table. You should also connect ground, but it works without it.

Select a 115200 baud rate, and open a serial connection to the FTDI serial device. After opening the connection, select the terminal, and press any key on your keyboard to input a character. You should see the character echoed back. (Character does a round-trip through the Teensy back to your PC.) If you do not see a character echoed back, either

If you see character's echoed back, you should be positioned to run the full demo. Keep the FTDI cable connected to your board.

Full demo

Keep all physical connections from the previous two tests. Flash the pwm-control demo to your board:

./task.py demo pwm-control

This generates the output target/thumbv7em-none-eabihf/release/demo-pwm-control.hex. Flash that to your board. You should see the LED blinking slowly.

Build all host-side support software, and run imu-parse.py. See instructions here. After running imu-parse.py, you should see a stream of 9DOF readings appear in your terminal. If you see an error about converting readings, just try again; you happened to connect in the middle of a message stream.

You should also be able to open a serial connection to the Teensy 4's USB serial device. You will not see a stream of MPU readings. Press r to get the state of the ESC controller. You should see SENSOR = CONNECTED, which indicates a connection to the MPU.

ebelski commented 3 years ago

Thank you for this!!! I'll give it a go later today.

mciantyre commented 3 years ago

Here's a simplified view of a breadboard layout. Ignore the part identifiers; the pinouts are still correct. Always wanted to try out this diagramming...

pwm-control

ebelski commented 3 years ago

Let's give it a go. Use whatever is on master right now: git checkout master. (a0c5cda as of this writing.)

Success

MPU to Teensy 4

Since it's a simpler demo, let's use the mpu9250-i2c example to make sure your MPU9250 is correctly connected to the Teensy 4. Build and flash the example:

./task.py demo mpu9250-i2c

This generates the output target/thumbv7em-none-eabihf/release/demo-mpu9250-i2c.hex. Flash that output to your board.

Success

Open a serial connection to the Teensy 4's USB output. Use PuTTY on Windows, or screen on *nix. Baud rate doesn't matter. About 20 seconds after flashing the mpu9250-i2c demo, you should see 9DOF readings appear at 4Hz. If you do not see these readings, it's likely that your connections to the MPU9250 are incorrect. See the connection instructions here. Make sure that the sensor is powered. If the issue persists, try to power-cycle the entire system; the MPU might be stuck in a strange state.

Success

If you see 9DOF readings at 4Hz, your connections to the MPU9250 and Teensy 4 are correct. Let's check the FTDI to Teensy 4 connection. Keep the MPU connected to your board.

FTDI to Teensy 4

test-ftdi.hex.zip

Download the above ZIP file. Unzip it to find test-ftdi.hex, and flash that HEX file to your Teensy 4. You should see the LED blinking. Connect your FTDI cable to the Teensy 4 as described in the table. You should also connect ground, but it works without it.

Success

Select a 115200 baud rate, and open a serial connection to the FTDI serial device. After opening the connection, select the terminal, and press any key on your keyboard to input a character. You should see the character echoed back. (Character does a round-trip through the Teensy back to your PC.) If you do not see a character echoed back, either

  • the connections between the FTDI and Teensy 4 are incorrect
  • there's an issue with your serial device, or an issue with your OS interface to your serial device

If you see character's echoed back, you should be positioned to run the full demo. Keep the FTDI cable connected to your board.

Success

Full demo

Keep all physical connections from the previous two tests. Flash the pwm-control demo to your board:

./task.py demo pwm-control

This generates the output target/thumbv7em-none-eabihf/release/demo-pwm-control.hex. Flash that to your board. You should see the LED blinking slowly.

Success

Build all host-side support software, and run imu-parse.py. See instructions here. After running imu-parse.py, you should see a stream of 9DOF readings appear in your terminal. If you see an error about converting readings, just try again; you happened to connect in the middle of a message stream.

I'm failing on this step. I was unable to get a successful connection after trying multiple times. I error out with the following message:

    readings = motion_sensor.convert_readings(buffer)
ValueError: error converting readings: DeserializeBadEncoding

You should also be able to open a serial connection to the Teensy 4's USB serial device. You will not see a stream of MPU readings. Press r to get the state of the ESC controller. You should see SENSOR = CONNECTED, which indicates a connection to the MPU.

Success

ebelski commented 3 years ago

@mciantyre, what's the binary encoding of the buffer? I tried utf-8 and ascii but neither of those worked (I was trying to decode the buffer to troubleshoot).

ebelski commented 3 years ago

Also that fritzing diagram is 🔥

mciantyre commented 3 years ago

I was unable to get a successful connection after trying multiple times.

Pull down the imu-parse-retry branch, and use the imu-parse.py script from that commit. Lets see if an automated retry loop helps. If not, we'll have to debug deeper.

what's the binary encoding of the buffer?

We serialize the readings using COBS. The representation of readings on the wire is an implementation detail, and it's not very readable.

https://github.com/ebelski/rust-copter/blob/a0c5cdaaf7e9ae6e49b709249cfb8f3d4cc759df/demos/pwm-control/src/main.rs#L71-L72

ebelski commented 3 years ago

That did the trick!

C:\Users\ebels\Desktop\rust-copter>python tools/imu-parse.py COM4
<class 'builtins.Acc'>: (0.129638671875, 0.121826171875, 0.864501953125)
<class 'builtins.Gyro'>: (-7.6751708984375, 0.7476806640625, -3.2806396484375)
<class 'builtins.Mag'>: (-111.32967376708984, 300.20587158203125, 181.54327392578125)
<class 'builtins.Acc'>: (0.126953125, 0.125, 0.87255859375)
<class 'builtins.Gyro'>: (-7.8887939453125, 0.69427490234375, -2.90679931640625)
<class 'builtins.Mag'>: (-111.32967376708984, 300.20587158203125, 181.54327392578125)
<class 'builtins.Acc'>: (0.123046875, 0.123779296875, 0.859375)
<class 'builtins.Gyro'>: (-7.89642333984375, 0.6866455078125, -3.07464599609375)
<class 'builtins.Mag'>: (-111.32967376708984, 314.1689453125, 194.9909210205078)