Skip to content
Snippets Groups Projects
Commit 081d50cb authored by ucart's avatar ucart
Browse files
parents a31fa857 5bfc1454
No related branches found
No related tags found
No related merge requests found
Showing
with 370 additions and 233 deletions
......@@ -4,4 +4,4 @@ set -e
# Quad Libraries and Boot image
(cd quad && make)
#(cd groundStation && make)
#(cd groundStation && make)
#!/bin/bash
set -e
export PATH=/usr/local/bin:$PATH
# Quad
cd quad && make && make test
(cd quad && make test)
......@@ -208,7 +208,7 @@ legend('Log', 'Model', 'location', 'northwest');
figure(6); subplot(2, 1, 1);
stairs(time, pitch_measured_IMU, '.-'); hold on; grid minor;
stairs(time_model_5ms, pitch_accel, '.-'); hold off;
title('Pitch Complimentary Filter Output');
title('Pitch Complementary Filter Output');
xlabel('Time (s)');
ylabel('Pitch Angle (rad)');
legend('Log', 'Model', 'location', 'northwest');
......@@ -216,9 +216,7 @@ legend('Log', 'Model', 'location', 'northwest');
subplot(2, 1, 2);
stairs(time, roll_measured_IMU, '.-'); hold on; grid minor;
stairs(time_model_5ms, roll_accel, '.-'); hold off;
title('Roll Complimentary Filter Output');
title('Roll Complementary Filter Output');
xlabel('Time (s)');
ylabel('Roll Angle (rad)');
legend('Log', 'Model', 'location', 'northwest');
temp = 1;
% Log Analysis Toggle
logAnalysisToggle = 1; % 1 for log analysis, 0 for normal operation
......@@ -43,9 +42,9 @@ temp = 1;
% Equilibrium height controller output
height_controlled_o = (((Rm*If + ...
+ (((omega0_o * 2 * Rm * Kv * Kq ...
+ (((omega0_o * 2 * Rm * Kv * Kq ...
* Kd + 1)^2) - 1)/(4* Rm*Kv^2*Kq ...
*Kd))/Vb)*(Pmax- Pmin)+Pmin);
* Kd))/Vb)*(Pmax- Pmin) + Pmin);
% Equilibrium positions
x_o = 0;
......@@ -67,133 +66,7 @@ temp = 1;
pitchrate_o = 0;
yawrate_o = 0;
% Import Data and determine errors
if logAnalysisToggle == 1 && temp == 0
% Import Data to Workspace
%data = importdata('loggingAnalysis/logFiles/logData.csv');
data = importdata('loggingAnalysis/logFiles/test.csv');
% Set up time vector
time = data.data(:, 1);
runtime = max(time);
% Determine x position error
x_setpoint = data.data(:, 25);
x_position = data.data(:, 20);
x_error = timeseries(x_setpoint - x_position, time);
% Determine y position error
y_setpoint = data.data(:, 26);
y_position = data.data(:, 21);
y_error = timeseries(y_setpoint - y_position, time);
% Determine z position error
z_setpoint = data.data(:, 27);
z_position = data.data(:, 22);
z_error = timeseries(z_setpoint - z_position, time);
% Determine pitch error
pitch_setpoint = data.data(:, 9);
pitch_value = data.data(:, 23);
pitch_error = timeseries(pitch_setpoint - pitch_value, time);
% Determine roll error
roll_setpoint = data.data(:, 10);
roll_value = data.data(:, 24);
roll_error = timeseries(roll_setpoint - roll_value, time);
% Determine yaw error
yaw_setpoint = zeros(length(time), 1); % NEEDS UPDATED WHEN LOG FILE INCLUDES YAW SETPOINT
yaw_value = data.data(:,10);%(length(time), 1); % NEEDS UPDATED WHEN LOG FILE INCLUDES YAW VALUE
yaw_error = timeseries(yaw_setpoint - yaw_value, time);
% Determine pitch rate error
pitchrate_setpoint = data.data(:, 11);
pitchrate_value = data.data(:, 6);
pitchrate_error = timeseries(pitchrate_setpoint - pitchrate_value, time);
% Determine roll rate error
rollrate_setpoint = data.data(:, 12);
rollrate_value = data.data(:, 5);
rollrate_error = timeseries(rollrate_setpoint - rollrate_value, time);
% Determine yaw rate error
yawrate_setpoint = data.data(:, 13);
yawrate_value = data.data(:, 7);
yawrate_error = timeseries(yawrate_setpoint - yawrate_value, time);
% Pull motor commands from log
x_command = data.data(:, 14);
y_command = data.data(:, 15);
z_command = data.data(:, 8);
yaw_command = data.data(:, 16);
%Create time series object for z command
throttle_command = timeseries(z_command, time);
% Determine signal mix PWM values
PWM0 = data.data(:, 28);
PWM1 = data.data(:, 29);
PWM2 = data.data(:, 30);
PWM3 = data.data(:, 31);
%Pull the measurements from the acceleratometer
raw_accel_data_x = data.data(:, 2);
raw_accel_data_y = data.data(:, 3);
raw_accel_data_z = data.data(:, 4);
raw_accel_data_arr = ...
[ raw_accel_data_x , raw_accel_data_y , raw_accel_data_z ];
raw_accel_data = timeseries( raw_accel_data_arr , time );
%Pull the measurements from the gyroscope
raw_gyro_data_x = data.data(:, 5);
raw_gyro_data_y = data.data(:, 6);
raw_gyro_data_z = data.data(:, 7);
raw_gyro_data_arr = ...
[ raw_gyro_data_x , raw_gyro_data_y , raw_gyro_data_z ];
raw_gyro_data = timeseries( raw_gyro_data_arr , time );
% Determine the initial height controller command
% height_controlled_o = 1; % NEEDS UPDATED WHEN LOG FILES INCLUDE THROTTLE COMMAND
% Determine the initial rotor speeds based on PWM inputs
u_P0 = (PWM0(1) - Pmin) / (Pmax - Pmin);
u_P1 = (PWM1(1) - Pmin) / (Pmax - Pmin);
u_P2 = (PWM2(1) - Pmin) / (Pmax - Pmin);
u_P3 = (PWM3(1) - Pmin) / (Pmax - Pmin);
Vb_eff_0 = u_P0 * Vb;
Vb_eff_1 = u_P1 * Vb;
Vb_eff_2 = u_P2 * Vb;
Vb_eff_3 = u_P3 * Vb;
omega0_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_0))) / (2*Rm*Kv*Kq*Kd);
omega1_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_1))) / (2*Rm*Kv*Kq*Kd);
omega2_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_2))) / (2*Rm*Kv*Kq*Kd);
omega3_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_3))) / (2*Rm*Kv*Kq*Kd);
% Determine initial positions for x, y, and z
x_o = x_position(1);
y_o = y_position(1);
z_o = z_position(1);
% Determine initial velocity for x, y, and z
x_vel_o = (x_position(2) - x_position(1)) / (time(2) - time(1));
y_vel_o = (y_position(2) - y_position(1)) / (time(2) - time(1));
z_vel_o = (z_position(2) - z_position(1)) / (time(2) - time(1));
% Determine initial angles
roll_o = roll_value(1);
pitch_o = pitch_value(1);
yaw_o = yaw_value(1);
% Determine initial angular rates
rollrate_o = rollrate_value(1);
pitchrate_o = pitchrate_value(1);
yawrate_o = yawrate_value(1);
elseif logAnalysisToggle == 1 && temp == 1
if logAnalysisToggle == 1
%%%%%% Commented out section until logging is .txt file based %%%%%%
% FNAME
% if you know the name of the log file that you want to parse, set the it
......@@ -218,6 +91,9 @@ elseif logAnalysisToggle == 1 && temp == 1
time = dataStruct.Time.data;
time = time - time(1);
time = time(1):0.005:time(length(time)-7);
time = time';
runtime = max(time);
% Determine x position error
......
function [loggedData, headers] = parse_log_model(filename, params, expData)
function [loggedData, headers] = parse_log_model(filename)
%parse_log This independent function parses the data stored in the file and
%returns a structure containing the data
% filename - this is the complete path of the file with the filename
......
No preview for this file type
......@@ -6,7 +6,7 @@ WS = $(CURDIR)/xsdk_workspace
BOOT = $(OUTDIR)/BOOT.bin
.PHONY: all libs zybo boot test clean deep-clean
.PHONY: all libs zybo boot run-virt-quad test clean deep-clean
all: libs bins
......@@ -31,10 +31,15 @@ gen_diagram:
boot: $(BOOT)
test:
run-virt-quad:
$(MAKE) -C src/virt_quad run
test: all
$(MAKE) -C src/queue test
$(MAKE) -C src/computation_graph test
$(MAKE) -C src/quad_app test
ruby scripts/tests/test_safety_checks.rb
ruby scripts/tests/test_unix_uart.rb
clean:
rm -rf $(INCDIR) $(LIBDIR) $(OUTDIR) $(EXEDIR)
......@@ -47,10 +52,9 @@ deep-clean:
$(MAKE) -C src/graph_blocks clean
$(MAKE) -C src/commands clean
$(MAKE) -C src/quad_app clean
bash scripts/clean_xsdk_workspace.sh
$(OUTDIR):
mkdir $(OUTDIR)
$(BOOT): zybo | $(OUTDIR)
bash scripts/create_zybo_boot.sh
bash scripts/xsdk/create_zybo_boot.sh
......@@ -6,12 +6,17 @@ the quad, and the XSDK main project that runs on the Zybo.
The main quad application is written as a library, and located at:
```
src/quad_app/quad_app.c
src/quad_app/ ("main" function in quad_app.c)
```
The main XSDK project that actually runs on the Zybo is located at:
```
xsdk_workspace/modular_quad_pid/main.c
xsdk_workspace/real_quad/
```
We also have a complemetary "virtual quad" to ease testing:
```
src/virt_quad/
```
## Building
......
#!/
import sys
print(sys.version_info)
import serial
if __name__ == '__main__':
data = bytes.fromhex('be040002001c0002000000d80471be5732703f9d16093f8bf7a03d0586ab3d006d3a40c1')
with serial.Serial('/dev/ttyUSB0', 115200) as ser:
ser.write(data)
File deleted
#!/usr/bin/python
import sys
print(sys.version_info)
import serial
if __name__ == '__main__':
data = bytes.fromhex('be040002001c0002000000d80471be5732703f9d16093f8bf7a03d0586ab3d006d3a40c1')
with serial.Serial('/dev/ttyUSB0', 921600) as ser:
ser.write(data)
#!/bin/bash
# Use the usb port on this machine that you are using for UART
USB_UART=ttyUSB0
MSG="\xbe\x04\x00\x02\x00\x1c\x00\x02\x00\x00\x00\xd8\x04\x71\xbe\x57\x32\x70\x3f\x9d\x16\x09\x3f\x8b\xf7\xa0\x3d\x05\x86\xab\x3d\x00\x6d\x3a\x40\xc1"
#MSG="\xbe\x04\x00\x02\x00\x1c\x00\x02\x00\x00\x00"
#MSG="hello"
echo -en $MSG > /dev/$USB_UART
\ No newline at end of file
#!/bin/bash
# The USB device that you are using for UART
USB_DEV=ttyUSB0
stty -F /dev/$USB_DEV raw speed 115200
#!/usr/bin/python
import sys
print(sys.version_info)
import serial
def create_msg(main_type, subtype, msg_id, data):
msg = bytes()
msg += b'\xBE'
msg += main_type.to_bytes(1, 'little')
msg += subtype.to_bytes(1, 'little')
msg += msg_id.to_bytes(2, 'little')
msg += len(data).to_bytes(2, 'little')
msg += data
checksum = 0
for b in msg:
checksum ^= b
msg += checksum.to_bytes(1, 'little')
return msg
def create_test_packet(size=8):
data = bytes((i % 256 for i in range(size)))
return create_msg(0, 2, 0, data)
def read_packet(ser):
header = ser.read(7)
length = int.from_bytes(header[5:7], byteorder='little')
data = ser.read(length)
checksum = ser.read()
return data
def query_received(ser):
# Send request
query_msg = create_msg(0, 3, 0, b'')
ser.write(query_msg)
ser.flush()
resp = read_packet(ser)
received_str = resp[:-1].decode()
return tuple(map(int, received_str.split(',')))
if __name__ == '__main__':
with serial.Serial('/dev/ttyUSB0', 921600, timeout=5) as ser:
ser.write(create_test_packet(500))
ser.flush()
print(query_received(ser))
#!/usr/bin/env ruby
# Test Flight
#
# A simple virtual test flight (take off, hover, and set back down)
#
THROTTLE_MIN = 110200
THROTTLE_MAX = 191900
THROTTLE_MID = (THROTTLE_MAX + THROTTLE_MIN)/2
THROTTLE_3_4 = (THROTTLE_MAX + THROTTLE_MID)/2
THROTTLE_QUAR = (THROTTLE_MID + THROTTLE_MIN)/2
THROTTLE_EIGHTH = (THROTTLE_QUAR + THROTTLE_MIN)/2
THROTTLE_16 = (THROTTLE_EIGHTH + THROTTLE_MIN)/2
MOTOR_MIN = 100000
MOTOR_MAX = 200000
GEAR_ON = 170800
GEAR_OFF = 118300
GRAVITY = 4096
MOTOR1 = "virt-quad-fifos/pwm-output-motor1"
MOTOR2 = "virt-quad-fifos/pwm-output-motor2"
MOTOR3 = "virt-quad-fifos/pwm-output-motor3"
MOTOR4 = "virt-quad-fifos/pwm-output-motor4"
UART_TX = "virt-quad-fifos/uart-tx"
GEAR = "virt-quad-fifos/pwm-input-gear"
THROTTLE = "virt-quad-fifos/pwm-input-throttle"
LED = "virt-quad-fifos/mio7-led"
I2C_MPU_ACCEL_X = "virt-quad-fifos/i2c-mpu-accel-x"
I2C_MPU_ACCEL_Y = "virt-quad-fifos/i2c-mpu-accel-y"
I2C_MPU_ACCEL_Z = "virt-quad-fifos/i2c-mpu-accel-z"
require 'test/unit/assertions'
require 'thread'
include Test::Unit::Assertions
script_dir = File.expand_path(File.dirname(__FILE__))
bin_dir = script_dir + "/../../bin/"
Dir.chdir(bin_dir)
# Start virtual quad
quad = Process.spawn("./virt-quad")
sleep 1
##################
# Begin Flight!
##################
begin
puts("Starting flight")
# Set gravity
File.write(I2C_MPU_ACCEL_Z, -1 * GRAVITY)
puts("Turning on GEAR...")
File.write(GEAR, GEAR_ON)
sleep 0.015
puts("Increasing Thrust to half maximum...")
for i in (THROTTLE_MIN..THROTTLE_MID).step(1000)
File.write(THROTTLE, i)
sleep 0.005
end
puts("Hovering for 10 seconds")
sleep 10
puts("Relaxing thrust to zero")
i = THROTTLE_MID
while i > THROTTLE_MIN
i -= 1000
File.write(THROTTLE, i)
sleep 0.005
end
puts("Swiching off GEAR...")
File.write(GEAR, GEAR_OFF)
# puts("Collecting logs...")
# msg = ""
# misses = 0
# fifo = File::open(UART_TX)
# while misses < 10
# puts "trying..."
# if fifo.eof?
# misses += 1
# next
# end
# msg += fifo.read()
# end
# fifo.close()
# puts msg
ensure
Process.kill(9, quad)
end
#!/usr/bin/env ruby
# Safety Checks
#
# Startup the virtual quad and make sure it doesn't allow combinations of things
# that could hurt people.
THROTTLE_MIN = 110200
THROTTLE_MAX = 191900
THROTTLE_MID = (THROTTLE_MAX + THROTTLE_MIN)/2
THROTTLE_3_4 = (THROTTLE_MAX + THROTTLE_MID)/2
THROTTLE_QUAR = (THROTTLE_MID + THROTTLE_MIN)/2
THROTTLE_EIGHTH = (THROTTLE_QUAR + THROTTLE_MIN)/2
THROTTLE_16 = (THROTTLE_EIGHTH + THROTTLE_MIN)/2
MOTOR_MIN = 100000
MOTOR_MAX = 200000
GEAR_ON = 170800
GEAR_OFF = 118300
GRAVITY = 4096
MOTOR1 = "virt-quad-fifos/pwm-output-motor1"
MOTOR2 = "virt-quad-fifos/pwm-output-motor2"
MOTOR3 = "virt-quad-fifos/pwm-output-motor3"
MOTOR4 = "virt-quad-fifos/pwm-output-motor4"
GEAR = "virt-quad-fifos/pwm-input-gear"
THROTTLE = "virt-quad-fifos/pwm-input-throttle"
LED = "virt-quad-fifos/mio7-led"
I2C_MPU_ACCEL_X = "virt-quad-fifos/i2c-mpu-accel-x"
I2C_MPU_ACCEL_Y = "virt-quad-fifos/i2c-mpu-accel-y"
I2C_MPU_ACCEL_Z = "virt-quad-fifos/i2c-mpu-accel-z"
require 'test/unit/assertions'
require 'thread'
include Test::Unit::Assertions
$fifos = Hash.new
def read_fifo_num(f)
if not $fifos.key?(f)
$fifos[f] = File.open(f)
end
$fifos[f].read().chomp.split("\n").last.to_i
end
# Utility functions
def check_motors_are_off
motor1 = read_fifo_num(MOTOR1)
motor2 = read_fifo_num(MOTOR2)
motor3 = read_fifo_num(MOTOR3)
motor4 = read_fifo_num(MOTOR4)
assert_operator motor1, :<=, THROTTLE_MIN
assert_operator motor2, :<=, THROTTLE_MIN
assert_operator motor3, :<=, THROTTLE_MIN
assert_operator motor4, :<=, THROTTLE_MIN
end
def get_motor_averages
motors = [[], [], [], []]
for i in 0..100
motors[0].push(read_fifo_num(MOTOR1))
motors[1].push(read_fifo_num(MOTOR2))
motors[2].push(read_fifo_num(MOTOR3))
motors[3].push(read_fifo_num(MOTOR4))
sleep 0.010
end
average = []
average[0] = motors[0].inject(:+).to_f / motors[0].size
average[1] = motors[1].inject(:+).to_f / motors[1].size
average[2] = motors[2].inject(:+).to_f / motors[2].size
average[3] = motors[3].inject(:+).to_f / motors[3].size
average
end
def check_led(on)
led = read_fifo_num(LED)
assert_equal(led, on)
end
script_dir = File.expand_path(File.dirname(__FILE__))
bin_dir = script_dir + "/../../bin/"
Dir.chdir(bin_dir)
# Start virtual quad
quad = Process.spawn("./virt-quad")
sleep 1
#################
# Begin Tests
#################
begin
puts("beginning tests")
# Set gravity
File.write(I2C_MPU_ACCEL_Z, -1 * GRAVITY)
puts("Check that motors are off at startup")
check_motors_are_off
puts("Check that LED is off at startup")
check_led(0)
puts("Check that increasing the throttle does nothing to motors")
# (because gear is still off)
for i in (THROTTLE_MIN..THROTTLE_MAX).step(1000)
File.write(THROTTLE, i)
check_motors_are_off
sleep 0.005
end
puts("Check that flipping gear to 1 while throttle is high does nothing")
# (motors should still be off, LED should still be off)
File.write(GEAR, GEAR_ON)
sleep 0.015
check_motors_are_off
i = THROTTLE_MAX
while i > THROTTLE_MID
i -= 1000
File.write(THROTTLE, i)
check_motors_are_off
check_led 0
sleep 0.005
end
# (swtich GEAR back to off and bring throttle off)
File.write(GEAR, GEAR_OFF)
File.write(THROTTLE, THROTTLE_MIN)
puts("Check that the LED turns on when gear is flipped on")
# (motors should still be off because our throttle is low)
File.write(GEAR, GEAR_ON)
sleep 0.020
check_led 1
check_motors_are_off
puts("Check that motors turn on")
File.write(THROTTLE, THROTTLE_MID)
averages = get_motor_averages
average = (averages[0] + averages[1] + averages[2] + averages[3])/4
puts averages, "(#{average})"
assert average.between?(THROTTLE_EIGHTH, MOTOR_MAX)
# Check that gear switch kills the motors
# (and that light goes off)
File.write(GEAR, GEAR_OFF)
sleep 0.040
check_motors_are_off
check_led 0
# (Bring the RC throttle back down)
File.write(THROTTLE, THROTTLE_MIN)
# Check that we can resume flight
File.write(GEAR, GEAR_ON)
sleep 0.040
check_led 1
sleep 1
puts "All safety checks passed."
ensure
Process.kill(9, quad)
end
#!/usr/bin/env ruby
# UART test
#
# This test is pretty simple, just a UART smoke test, using
# the debug callback on the quad
GEAR_ON = 170800
GEAR_OFF = 118300
GEAR = "virt-quad-fifos/pwm-input-gear"
UART_RX = "virt-quad-fifos/uart-rx"
UART_TX = "virt-quad-fifos/uart-tx"
require 'test/unit/assertions'
require 'thread'
include Test::Unit::Assertions
script_dir = File.expand_path(File.dirname(__FILE__))
bin_dir = script_dir + "/../../bin/"
Dir.chdir(bin_dir)
# Start virtual quad
quad = Process.spawn("./virt-quad")
sleep 1
#################
# Begin Tests
#################
begin
# Flip gear on
File.write(GEAR, GEAR_ON)
sleep 0.015
for j in 1..10
# Send a debug command
File.write(UART_RX, [0xBE, 1, 0, 0, 0, 0, 0, 0xBF].pack("CCCCCCCC"))
fifo = File.open(UART_TX)
msg = []
for i in 1..7
sleep 0.010
msg.push(fifo.read(1))
end
length = msg[5..7].join().unpack("S")[0]
msg = []
for i in 1..length
sleep 0.010
msg.push(fifo.read(1))
end
fifo.close
puts msg.join()
assert_equal(msg.join().force_encoding("UTF-8"), "Packets received: #{j}")
end
puts "Basic UART test passed."
ensure
Process.kill(9, quad)
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment