Lab7 code.cpp
· 6.2 KiB · C++
Raw
///////////////////////////////////////////////////////////////////////////////////////////////
// SINEIO
///////////////////////////////////////////////////////////////////////////////////////////////
#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES // for C++
#include <cmath>
#include <time.h>
#include <fstream>
#include "IIRdf1filt.h"
#include "../myWin826.h"
#include "../826api.h"
#include "../RealTime.h"
#define SAMPLE_RATE 1000 // Hz
#define MAX_LOOP_TIME 2 //seconds
#define RECORD_LENGTH (MAX_LOOP_TIME*SAMPLE_RATE)
// IO card configuration constants
#define IO_BOARD_NUM 0 // no change
#define ADC_SLOT 0 // no change
#define DAC_ZERO_OUTPUT 0x8000
#define DAC_CONFIG_GAIN S826_DAC_SPAN_10_10 // -10 to 10 spans 20 volts so...
#define DAC_VRANGE 20.0 // This MUST correspond to the DAC_SPAN just above
#define DAC_CNT_RANGE 0xFFFF // 16-bit DAC
#define DAC_OFFSET_COUNTS 0x8000 // 32768 offset for a signed desired output mapped to unsigned DAC write.
#define DAC_CHANNEL 1 // SET ME! CHECK YOUR SETUP: DAC channel output
#define ADC_CHANNEL 0 // SET ME! CHECK YOUR SETUP: analog input channel to track
#define ADC_CNT_RANGE 0xFFFF // 2^16= 0xFFFF (16 bit converter)
#define ADC_GAIN S826_ADC_GAIN_1 // -10 to 10 option
#define ADC_VRANGE 20 // this must correspond to gain setting
#define ADC_ENABLE 1
#define SINE_FREQ 5.0 // Hz
#define SINE_MAG 250 // counts
/* Coeficients for your second-order filter from matlab (Butter() or other IIR filter... */
/* These are junk values so replace with your design */
const double a[] = { 1.000000000000000, -1.991114292201654, 0.991153595868935 };
const double b[] = { 0.995566972017647, -1.991133944035295, 0.995566972017647 };
int main()
{
int errcode = S826_ERR_OK;
int boardflags = S826_SystemOpen(); // open 826 driver and find all 826 boards
int ncount = 0;
uint dacout;
double voltageout = 0;
double Amp = 0;
double Frequency = 0;
double Ti = 0;
double Td = 0;
double Kp = 0.008; // Proportional gain
double Ki = 0;//Kp/Ti; // Integral gain
double Kd = 0;//Kp*Td; // Derivative gain
int current_position = 0; // Actual position from encoder
double ref_position = 0; // Desired position
int error = 0; // Control error
double error_derivative = 0; // Derivative of error
double integrated_error = 0; // Integral of error
int previous_error = 0; // Previous error for derivative calculation
char key = '0'; // Keyboard input
double t = 0; // time variable for sine wave
// Data collection variables
int data_log[2000];
int ref_log[2000]; // track position reference
int log_index = 0;
// encoder interface
uint start_count;
uint counts;
int rawcounts[RECORD_LENGTH];
double filtcounts[RECORD_LENGTH];
// real-time filter
int N = sizeof(a) / sizeof(double); // number of a's and b's. filter order plus 1.
IIRdf1filt filter(N, a, b); // instantiate and initialize the filter
// file output
int i;
char outfileName[30];
counts = 0;
// instantiate our "real time" object that will pace our loop
RealTime realTime(SAMPLE_RATE);
// Configure data acquisition interfaces and start them running.
X826(S826_AdcSlotConfigWrite(IO_BOARD_NUM, ADC_SLOT, ADC_CHANNEL, 0, ADC_GAIN)); // program adc timeslot attributes: slot, chan, 0us settling time. For -5V-5V use: "S826_ADC_GAIN_2"
X826(S826_AdcSlotlistWrite(IO_BOARD_NUM, 1 << ADC_SLOT, S826_BITWRITE)); // enable adc timeslot; disable all other slots
X826(S826_AdcEnableWrite(IO_BOARD_NUM, ADC_ENABLE)); // enable adc conversions
X826(S826_DacRangeWrite(IO_BOARD_NUM, DAC_CHANNEL, DAC_CONFIG_GAIN, 0)); // program dac output range: -10V to +10V
// Initialize Motor Shaft Encoder Interface
S826_CounterModeWrite(0, 0, S826_CM_K_QUADX1); // Configure counter0 as incremental encoder interface.
S826_CounterStateWrite(0, 0, 1); // Start tracking encoder position.
S826_CounterRead(0, 0, &start_count); // Read initial encoder counts
// commence pseudo-real-time loop.
realTime.Start();
while (key != 'q')
{
// Calculate current time 't'
t = (double)ncount / SAMPLE_RATE;
// Generate sine wave signal
ref_position = SINE_MAG * sin(2.0 * M_PI * SINE_FREQ * t);
// scale the desired voltage to the DAC integer output.
dacout = (uint)(voltageout * (DAC_CNT_RANGE / DAC_VRANGE) + DAC_OFFSET_COUNTS);
// output to the DAC
X826(S826_DacDataWrite(IO_BOARD_NUM, DAC_CHANNEL, dacout, 0));
S826_CounterRead(0, 0, &counts); // Read current encoder counts.
counts = counts - start_count; // Subtracting the initial counts so we begin from 0
error = (int)ref_position - counts;
integrated_error += error * (1.00 / SAMPLE_RATE);
error_derivative = (error - previous_error) / (1.00 / SAMPLE_RATE);
previous_error = error;
voltageout = Kp * error + Kd * error_derivative + Ki * integrated_error;
//Saftey
if (voltageout > 10.0) voltageout = 10.0;
if (voltageout < -10.0) voltageout = -10.0;
// 1. Read Keyboard Input
if (_kbhit()) // if you hit a key keyboard then read input
{
key = _getch();
if (key == 'M') ref_position += 500; // 'right arrow key' increments ref
else if (key == 'K') ref_position -= 500; // 'left arrow key' decrements ref ;
}
if (log_index < 2000) {
data_log[log_index] = counts;
ref_log[log_index] = (int)ref_position;
log_index++;
}
realTime.Sleep();
ncount++;
}
realTime.Stop(ncount); // stop real-time loop
X826(S826_DacDataWrite(IO_BOARD_NUM, DAC_CHANNEL, DAC_ZERO_OUTPUT, 0)); // put to zero at the end
S826_SystemClose();
// file output
printf("\nType in a file name (freq_amp like 50_10 for 5Hz, 1V is a good idea):\n");
scanf("%s", outfileName);
std::ofstream outfile(strcat(outfileName, ".txt")); // our test file to filter
outfile << "Counts,Reference:\n";
//outfile << Frequency << "," << Amp << "\n";
// Write raw data to first column of output file
for (i = 0; i < log_index; i++)
{
outfile << data_log[i] << "," << ref_log[i] << "\n";
}
outfile.close();
return 0;
}
| 1 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 2 | // SINEIO |
| 3 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 4 | |
| 5 | #define _CRT_SECURE_NO_WARNINGS |
| 6 | #define _USE_MATH_DEFINES // for C++ |
| 7 | #include <cmath> |
| 8 | #include <time.h> |
| 9 | #include <fstream> |
| 10 | #include "IIRdf1filt.h" |
| 11 | #include "../myWin826.h" |
| 12 | #include "../826api.h" |
| 13 | #include "../RealTime.h" |
| 14 | |
| 15 | #define SAMPLE_RATE 1000 // Hz |
| 16 | #define MAX_LOOP_TIME 2 //seconds |
| 17 | #define RECORD_LENGTH (MAX_LOOP_TIME*SAMPLE_RATE) |
| 18 | |
| 19 | |
| 20 | // IO card configuration constants |
| 21 | #define IO_BOARD_NUM 0 // no change |
| 22 | #define ADC_SLOT 0 // no change |
| 23 | |
| 24 | #define DAC_ZERO_OUTPUT 0x8000 |
| 25 | #define DAC_CONFIG_GAIN S826_DAC_SPAN_10_10 // -10 to 10 spans 20 volts so... |
| 26 | #define DAC_VRANGE 20.0 // This MUST correspond to the DAC_SPAN just above |
| 27 | #define DAC_CNT_RANGE 0xFFFF // 16-bit DAC |
| 28 | #define DAC_OFFSET_COUNTS 0x8000 // 32768 offset for a signed desired output mapped to unsigned DAC write. |
| 29 | |
| 30 | #define DAC_CHANNEL 1 // SET ME! CHECK YOUR SETUP: DAC channel output |
| 31 | |
| 32 | #define ADC_CHANNEL 0 // SET ME! CHECK YOUR SETUP: analog input channel to track |
| 33 | |
| 34 | |
| 35 | #define ADC_CNT_RANGE 0xFFFF // 2^16= 0xFFFF (16 bit converter) |
| 36 | #define ADC_GAIN S826_ADC_GAIN_1 // -10 to 10 option |
| 37 | #define ADC_VRANGE 20 // this must correspond to gain setting |
| 38 | |
| 39 | |
| 40 | #define ADC_ENABLE 1 |
| 41 | |
| 42 | |
| 43 | #define SINE_FREQ 5.0 // Hz |
| 44 | #define SINE_MAG 250 // counts |
| 45 | |
| 46 | /* Coeficients for your second-order filter from matlab (Butter() or other IIR filter... */ |
| 47 | /* These are junk values so replace with your design */ |
| 48 | const double a[] = { 1.000000000000000, -1.991114292201654, 0.991153595868935 }; |
| 49 | const double b[] = { 0.995566972017647, -1.991133944035295, 0.995566972017647 }; |
| 50 | |
| 51 | int main() |
| 52 | { |
| 53 | int errcode = S826_ERR_OK; |
| 54 | int boardflags = S826_SystemOpen(); // open 826 driver and find all 826 boards |
| 55 | int ncount = 0; |
| 56 | uint dacout; |
| 57 | |
| 58 | double voltageout = 0; |
| 59 | |
| 60 | double Amp = 0; |
| 61 | double Frequency = 0; |
| 62 | |
| 63 | |
| 64 | double Ti = 0; |
| 65 | double Td = 0; |
| 66 | double Kp = 0.008; // Proportional gain |
| 67 | double Ki = 0;//Kp/Ti; // Integral gain |
| 68 | double Kd = 0;//Kp*Td; // Derivative gain |
| 69 | int current_position = 0; // Actual position from encoder |
| 70 | double ref_position = 0; // Desired position |
| 71 | int error = 0; // Control error |
| 72 | double error_derivative = 0; // Derivative of error |
| 73 | double integrated_error = 0; // Integral of error |
| 74 | int previous_error = 0; // Previous error for derivative calculation |
| 75 | char key = '0'; // Keyboard input |
| 76 | |
| 77 | double t = 0; // time variable for sine wave |
| 78 | |
| 79 | // Data collection variables |
| 80 | int data_log[2000]; |
| 81 | int ref_log[2000]; // track position reference |
| 82 | int log_index = 0; |
| 83 | |
| 84 | // encoder interface |
| 85 | uint start_count; |
| 86 | uint counts; |
| 87 | int rawcounts[RECORD_LENGTH]; |
| 88 | double filtcounts[RECORD_LENGTH]; |
| 89 | |
| 90 | // real-time filter |
| 91 | int N = sizeof(a) / sizeof(double); // number of a's and b's. filter order plus 1. |
| 92 | IIRdf1filt filter(N, a, b); // instantiate and initialize the filter |
| 93 | |
| 94 | // file output |
| 95 | int i; |
| 96 | char outfileName[30]; |
| 97 | |
| 98 | counts = 0; |
| 99 | |
| 100 | // instantiate our "real time" object that will pace our loop |
| 101 | RealTime realTime(SAMPLE_RATE); |
| 102 | |
| 103 | // Configure data acquisition interfaces and start them running. |
| 104 | X826(S826_AdcSlotConfigWrite(IO_BOARD_NUM, ADC_SLOT, ADC_CHANNEL, 0, ADC_GAIN)); // program adc timeslot attributes: slot, chan, 0us settling time. For -5V-5V use: "S826_ADC_GAIN_2" |
| 105 | X826(S826_AdcSlotlistWrite(IO_BOARD_NUM, 1 << ADC_SLOT, S826_BITWRITE)); // enable adc timeslot; disable all other slots |
| 106 | X826(S826_AdcEnableWrite(IO_BOARD_NUM, ADC_ENABLE)); // enable adc conversions |
| 107 | X826(S826_DacRangeWrite(IO_BOARD_NUM, DAC_CHANNEL, DAC_CONFIG_GAIN, 0)); // program dac output range: -10V to +10V |
| 108 | |
| 109 | // Initialize Motor Shaft Encoder Interface |
| 110 | S826_CounterModeWrite(0, 0, S826_CM_K_QUADX1); // Configure counter0 as incremental encoder interface. |
| 111 | S826_CounterStateWrite(0, 0, 1); // Start tracking encoder position. |
| 112 | S826_CounterRead(0, 0, &start_count); // Read initial encoder counts |
| 113 | |
| 114 | // commence pseudo-real-time loop. |
| 115 | realTime.Start(); |
| 116 | |
| 117 | while (key != 'q') |
| 118 | { |
| 119 | // Calculate current time 't' |
| 120 | t = (double)ncount / SAMPLE_RATE; |
| 121 | |
| 122 | // Generate sine wave signal |
| 123 | ref_position = SINE_MAG * sin(2.0 * M_PI * SINE_FREQ * t); |
| 124 | |
| 125 | // scale the desired voltage to the DAC integer output. |
| 126 | dacout = (uint)(voltageout * (DAC_CNT_RANGE / DAC_VRANGE) + DAC_OFFSET_COUNTS); |
| 127 | |
| 128 | // output to the DAC |
| 129 | X826(S826_DacDataWrite(IO_BOARD_NUM, DAC_CHANNEL, dacout, 0)); |
| 130 | |
| 131 | S826_CounterRead(0, 0, &counts); // Read current encoder counts. |
| 132 | counts = counts - start_count; // Subtracting the initial counts so we begin from 0 |
| 133 | |
| 134 | error = (int)ref_position - counts; |
| 135 | integrated_error += error * (1.00 / SAMPLE_RATE); |
| 136 | error_derivative = (error - previous_error) / (1.00 / SAMPLE_RATE); |
| 137 | previous_error = error; |
| 138 | voltageout = Kp * error + Kd * error_derivative + Ki * integrated_error; |
| 139 | |
| 140 | //Saftey |
| 141 | if (voltageout > 10.0) voltageout = 10.0; |
| 142 | if (voltageout < -10.0) voltageout = -10.0; |
| 143 | |
| 144 | // 1. Read Keyboard Input |
| 145 | if (_kbhit()) // if you hit a key keyboard then read input |
| 146 | { |
| 147 | key = _getch(); |
| 148 | if (key == 'M') ref_position += 500; // 'right arrow key' increments ref |
| 149 | else if (key == 'K') ref_position -= 500; // 'left arrow key' decrements ref ; |
| 150 | } |
| 151 | |
| 152 | if (log_index < 2000) { |
| 153 | data_log[log_index] = counts; |
| 154 | ref_log[log_index] = (int)ref_position; |
| 155 | log_index++; |
| 156 | } |
| 157 | |
| 158 | realTime.Sleep(); |
| 159 | ncount++; |
| 160 | } |
| 161 | |
| 162 | realTime.Stop(ncount); // stop real-time loop |
| 163 | |
| 164 | X826(S826_DacDataWrite(IO_BOARD_NUM, DAC_CHANNEL, DAC_ZERO_OUTPUT, 0)); // put to zero at the end |
| 165 | S826_SystemClose(); |
| 166 | |
| 167 | // file output |
| 168 | printf("\nType in a file name (freq_amp like 50_10 for 5Hz, 1V is a good idea):\n"); |
| 169 | scanf("%s", outfileName); |
| 170 | |
| 171 | std::ofstream outfile(strcat(outfileName, ".txt")); // our test file to filter |
| 172 | |
| 173 | outfile << "Counts,Reference:\n"; |
| 174 | //outfile << Frequency << "," << Amp << "\n"; |
| 175 | |
| 176 | // Write raw data to first column of output file |
| 177 | for (i = 0; i < log_index; i++) |
| 178 | { |
| 179 | outfile << data_log[i] << "," << ref_log[i] << "\n"; |
| 180 | } |
| 181 | |
| 182 | outfile.close(); |
| 183 | |
| 184 | return 0; |
| 185 | } |