summaryrefslogtreecommitdiffstats
path: root/Kod/bilbana
diff options
context:
space:
mode:
Diffstat (limited to 'Kod/bilbana')
-rw-r--r--Kod/bilbana/IOFunctions/config_IOs.m191
-rw-r--r--Kod/bilbana/IOFunctions/get_car_position.m81
-rw-r--r--Kod/bilbana/IOFunctions/get_manual_speed.m279
-rw-r--r--Kod/bilbana/IOFunctions/initialize_counters.m217
-rw-r--r--Kod/bilbana/IOFunctions/set_car_speed.m56
-rw-r--r--Kod/bilbana/IOFunctions/start_race.m56
-rw-r--r--Kod/bilbana/IOFunctions/terminate.m83
-rw-r--r--Kod/bilbana/run_scalectrix.m47
-rw-r--r--Kod/bilbana/studentFunctions/car_controller.m16
-rw-r--r--Kod/bilbana/studentFunctions/init_car.m25
-rw-r--r--Kod/bilbana/studentFunctions/plot_results.m15
-rw-r--r--Kod/bilbana/studentFunctions/run_simple_example.m41
-rw-r--r--Kod/bilbana/studentFunctions/update_control.m16
-rw-r--r--Kod/bilbana/studentFunctions/update_position.m39
14 files changed, 1162 insertions, 0 deletions
diff --git a/Kod/bilbana/IOFunctions/config_IOs.m b/Kod/bilbana/IOFunctions/config_IOs.m
new file mode 100644
index 0000000..0a84d2a
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/config_IOs.m
@@ -0,0 +1,191 @@
+function [] = config_IOs()
+%cCONFIG_IOS Configurates the input and output digital channels
+%
+% Starts tasks for 5 digital channels, 3 output and 2 input channels.
+% There is one channel per task.
+%
+% These channels corresponds to:
+%
+% Output channels:
+% SCLK - Serial Clock Input.
+% CS_INV - Active-Low Chip Select. Data will not be clocked into DIN
+% unless CS is low. When CS is high, DOUT is high impedance.
+% DIN - Digital Serial Input. Data is clocked in at the rising edge of
+% SCLK.
+%
+% Input channels:
+% SSTRB - Serial Strobe Output. In internal clock mode, SSTRB goes low
+% when the MAX186/MAX188 begin the A/D conversion and goes high
+% when the conversion is done. In external clock mode, SSTRB
+% pulses high for one clock period before the MSB decision. High
+% impedance when CS is high (external mode).
+% DOUT - Serial Data Output. Data is clocked out at the falling edge of
+% SCLK. High impedance when CS is high.
+%
+% These channels corresponds to pin 19 - 15 on the ADC MAXIM MAX186 chip.
+%
+% Tobias Lindell - 2013-02-12
+
+global mytaskh
+global lib
+
+DAQmx_Val_ChanPerLine =0; % One Channel For Each Line
+DAQmx_Val_ChanForAllLines =1; %#ok<NASGU> % One Channel For All Lines
+
+if isempty(lib)
+ lib = 'myni'; % library alias
+ if ~libisloaded(lib)
+ disp('Matlab: Load nicaiu.dll')
+ funclist = loadlibrary('c:\windows\system32\nicaiu.dll','C:\Program Files (x86)\National Instruments\Shared\ExternalCompilerSupport\C\include\nidaqmx.h','alias',lib); %#ok<NASGU>
+ %if you do NOT have nicaiu.dll and nidaqmx.h
+ %in your Matlab path,add full pathnames or copy the files.
+ %libfunctions(lib,'-full') % use this to show the...
+ %libfunctionsview(lib) % included function
+ disp('Matlab: Nicaiu.dll loaded!')
+ end
+end
+
+% DOlines = {'Dev1/port0/line0','Dev1/port0/line1','Dev1/port0/line2'};
+lineGrouping = DAQmx_Val_ChanPerLine; % One Channel For Each Line
+mytaskh.DO_SCLK = DAQmxCreateDOChan(lib,'Dev1/port0/line0',lineGrouping);
+mytaskh.DO_CS_INV = DAQmxCreateDOChan(lib,'Dev1/port0/line1',lineGrouping);
+mytaskh.DO_DIN = DAQmxCreateDOChan(lib,'Dev1/port0/line2',lineGrouping);
+
+% DIlines = {'Dev1/port0/line3','Dev1/port0/line4'};
+mytaskh.DI_SSTRB = DAQmxCreateDIChan(lib,'Dev1/port0/line3',lineGrouping);
+mytaskh.DI_DOUT = DAQmxCreateDIChan(lib,'Dev1/port0/line4',lineGrouping);
+
+end
+
+function taskh = DAQmxCreateDIChan(lib,lines,lineGrouping)
+% function taskh = DAQmxCreateDIChan(lib,lines,lineGrouping)
+%
+% this function creates a task and adds digital output line(s) to the task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% lines - line(s) to add to task
+% 1 line example: 'Dev1/port0/line0'
+% 2 lines example: {'Dev1/port0/line0','Dev1/port0/line1'}
+% passing as .../line0-1 probably also works, but I didn't test
+% lineGrouping - either DAQmx_Val_ChanPerLine or DAQmx_Val_ChanForAllLines
+%
+%
+% C functions used:
+% int32 DAQmxCreateTask (const char taskName[],TaskHandle *taskHandle);
+% int32 DAQmxCreateDIChan (TaskHandle taskHandle,const char lines[],const char nameToAssignToLines[],int32 lineGrouping);
+% int32 DAQmxTaskControl (TaskHandle taskHandle,int32 action);
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+
+% create task
+taskh = [];
+name_task = ''; % recommended to avoid problems
+[err,~,taskh] = calllib(lib,'DAQmxCreateTask',name_task,uint32(taskh));
+DAQmxCheckError(lib,err);
+
+% % check whether done
+% [err,b,istaskdone] = calllib(lib,'DAQmxIsTaskDone',(taskh),0);
+% DAQmxCheckError(lib,err);
+
+% create DI channel(s) and add to task
+% numchan = numel(lines);
+name_line = ''; % recommended to avoid problems
+if ~iscell(lines) % just 1 channel
+ [err,~,~,~] = calllib(lib,'DAQmxCreateDIChan',taskh,lines,name_line,lineGrouping);
+ DAQmxCheckError(lib,err);
+else % more than 1 channel to add to task
+ for m = 1:numel(lines) % loop to add channels
+ [err,~,~,~] = calllib(lib,'DAQmxCreateDIChan',taskh,lines{m},name_line,lineGrouping);
+ DAQmxCheckError(lib,err);
+ end
+end
+
+% verify everything OK
+DAQmx_Val_Task_Verify =2; % Verify
+[err,~] = calllib(lib,'DAQmxTaskControl',taskh,DAQmx_Val_Task_Verify);
+DAQmxCheckError(lib,err);
+end
+
+function taskh = DAQmxCreateDOChan(lib,lines,lineGrouping)
+% function taskh = DAQmxCreateDOChan(lib,lines,lineGrouping)
+%
+% this function creates a task and adds digital output line(s) to the task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% lines - line(s) to add to task
+% 1 line example: 'Dev1/port0/line0'
+% 2 lines example: {'Dev1/port0/line0','Dev1/port0/line1'}
+% passing as .../line0-1 probably also works, but I didn't test
+% lineGrouping - either DAQmx_Val_ChanPerLine or DAQmx_Val_ChanForAllLines
+%
+%
+% C functions used:
+% int32 DAQmxCreateTask (const char taskName[],TaskHandle *taskHandle);
+% int32 DAQmxCreateDOChan (TaskHandle taskHandle,const char lines[],const char nameToAssignToLines[],int32 lineGrouping);
+% int32 DAQmxTaskControl (TaskHandle taskHandle,int32 action);
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+
+% create task
+taskh = [];
+name_task = ''; % recommended to avoid problems
+[err,~,taskh] = calllib(lib,'DAQmxCreateTask',name_task,uint32(taskh));
+DAQmxCheckError(lib,err);
+
+% % check whether done
+% [err,b,istaskdone] = calllib(lib,'DAQmxIsTaskDone',(taskh),0);
+% DAQmxCheckError(lib,err);
+
+% create DO channel(s) and add to task
+name_line = ''; % recommended to avoid problems
+if ~iscell(lines)
+ [err,~,~,~] = calllib(lib,'DAQmxCreateDOChan',taskh,lines,name_line,lineGrouping);
+ DAQmxCheckError(lib,err);
+else % more than 1 channel to add to task
+ for m = 1:numel(lines)
+ [err,~,~,~] = calllib(lib,'DAQmxCreateDOChan',taskh,lines{m},name_line,lineGrouping);
+ DAQmxCheckError(lib,err);
+ end
+end
+
+% verify everything OK
+DAQmx_Val_Task_Verify = 2; % Verify
+[err,~] = calllib(lib,'DAQmxTaskControl',taskh,DAQmx_Val_Task_Verify);
+DAQmxCheckError(lib,err);
+end
+
+function DAQmxCheckError(lib,err)
+% function DAQmxCheckError(lib,err)
+%
+% read error code
+% zero means no error - does nothing
+% nonzero - find out error string and generate error
+%
+% inputs:
+% lib = .dll or alias (ex. 'myni')
+% err = DAQmx error
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+if err ~= 0
+ % find out how long the error string is
+ [numerr,~] = calllib(lib,'DAQmxGetErrorString',err,'',0);
+
+ % get error string
+ errstr = char(1:numerr); % have to pass dummy string of correct length
+ [~,errstr] = calllib(lib,'DAQmxGetErrorString',err,errstr,numerr);
+
+ % matlab error
+ error(['DAQmx error - ',errstr])
+end
+end \ No newline at end of file
diff --git a/Kod/bilbana/IOFunctions/get_car_position.m b/Kod/bilbana/IOFunctions/get_car_position.m
new file mode 100644
index 0000000..ef68fc2
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/get_car_position.m
@@ -0,0 +1,81 @@
+function [add_lap,add_check_point,elapsed_time_check_point] = get_car_position(track)
+%GET_CAR_POSITION Reads the current values of the lap and check point
+%counters, and resets them if they are not equal to zero.
+%
+% Tobias Lindell 2013-02-13
+
+global mytaskh
+global lib
+
+switch nargin
+ case 1
+ add_lap = [];
+ add_check_point = [];
+ elapsed_time_check_point = [];
+
+ if isempty(mytaskh)
+ disp(['User needs to initialize counters for track ',num2str(track),' before getting car position!'])
+ clearvars -global mytaskh lib
+ return
+ end
+
+ switch track
+ case 1
+ if isfield(mytaskh,'ctr_1')
+ add_check_point = DAQmxReadCounterScalarU32(lib,mytaskh.ctr_1);
+ add_lap = DAQmxReadCounterScalarU32(lib,mytaskh.ctr_2);
+ read_ticks = DAQmxReadCounterScalarU32(lib,mytaskh.ctr_3);
+ else
+ disp(['User needs to initialize counters for track ',num2str(track),' before getting car position!'])
+ return
+ end
+ case 2
+ if isfield(mytaskh,'ctr_5')
+ add_check_point = DAQmxReadCounterScalarU32(lib,mytaskh.ctr_5);
+ add_lap = DAQmxReadCounterScalarU32(lib,mytaskh.ctr_6);
+ read_ticks = DAQmxReadCounterScalarU32(lib,mytaskh.ctr_7);
+ else
+ disp(['User needs to initialize counters for track ',num2str(track),' before getting car position!'])
+ return
+ end
+
+ otherwise
+ disp('Wrong track number sent to get_car_position!')
+ return
+ end
+
+ if add_check_point || add_lap
+ elapsed_time_check_point = read_ticks / 100;
+ start_race(track);
+ clear read_ticks
+ end
+ otherwise
+ disp('Wrong number of input arguments sent to get_car_position(track)! Should be 1!')
+end
+end
+
+function Data = DAQmxReadCounterScalarU32(lib,taskh)
+% function taskh = DAQmxReadCounterScalarU32(lib,taskh)
+%
+% this function reads a counter value from previously setup task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% taskh - taskhandle of analog inputs
+%
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+DAQmx_Val_WaitInfinitely = -1.0;
+
+reserved = [];
+reserved_ptr = libpointer('uint32Ptr',reserved);
+Data = 1;
+data_ptr = libpointer('uint32Ptr',Data);
+calllib(lib,'DAQmxReadCounterScalarU32',taskh,DAQmx_Val_WaitInfinitely,data_ptr,reserved_ptr);
+counter = get(data_ptr);
+Data = counter.Value;
+end
+
diff --git a/Kod/bilbana/IOFunctions/get_manual_speed.m b/Kod/bilbana/IOFunctions/get_manual_speed.m
new file mode 100644
index 0000000..04af0ae
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/get_manual_speed.m
@@ -0,0 +1,279 @@
+function [manual_speed] = get_manual_speed(track)
+%GET_MANUAL_SPEED Reads input from gas handle and returns converted value.
+% Uses digital in/out functions to get and set values on the channels set
+% up by the function config_IOs.
+%
+% Output channels:
+% SCLK - Serial Clock Input.
+% CS_INV - Active-Low Chip Select. Data will not be clocked into DIN
+% unless CS is low. When CS is high, DOUT is high impedance.
+% DIN - Digital Serial Input. Data is clocked in at the rising edge of
+% SCLK.
+%
+% Input channels:
+% SSTRB - Serial Strobe Output. In internal clock mode, SSTRB goes low
+% when the MAX186/MAX188 begin the A/D conversion and goes high
+% when the conversion is done. In external clock mode, SSTRB
+% pulses high for one clock period before the MSB decision. High
+% impedance when CS is high (external mode).
+% DOUT - Serial Data Output. Data is clocked out at the falling edge of
+% SCLK. High impedance when CS is high.
+%
+% User needs to manually clock the serial clock of the analog/digital
+% converter to read or write data.
+%
+% Tobias Lindell - 2013-02-12
+
+global mytaskh
+global lib
+
+switch nargin
+ case 1
+ manual_speed = [];
+
+ if isempty(mytaskh)
+ disp('User needs to initialize IO before getting manual car speed!')
+ clearvars -global mytaskh lib
+ return
+ else
+ if ~isfield(mytaskh,'DO_SCLK')
+ disp('User needs to initialize IO before getting manual car speed!')
+ return
+ end
+ end
+
+ switch track
+ case 1
+ control_bit = 0;
+ case 2
+ control_bit = 1;
+ otherwise
+ disp('Wrong track number sent to get_manual_speed!')
+ return
+ end
+
+ % Channels:
+ % mytaskh.DO_SCLK
+ % mytaskh.DO_CS_INV
+ % mytaskh.DO_DIN
+ % mytaskh.DI_SSTRB
+ % mytaskh.DI_DOUT
+
+ DAQmx_Val_ChanPerLine =0; %#ok<*NASGU> % One Channel For Each Line
+ DAQmx_Val_ChanForAllLines =1; % One Channel For All Lines
+ DAQmx_Val_GroupByChannel = 0; % Group by Channel
+ DAQmx_Val_GroupByScanNumber =1; % Group by Scan Number
+
+ numSampsPerChan = 1;
+ timeout = 1;
+ fillMode = DAQmx_Val_GroupByChannel; % Group by Channel
+ % fillMode = DAQmx_Val_GroupByScanNumber; % Group by Scan Number
+ dataLayout = DAQmx_Val_GroupByChannel; % Group by Channel
+ % dataLayout = DAQmx_Val_GroupByScanNumber; % Group by Scan Number
+ numchanDI = 1; % DI lines
+ numsample = 1;
+
+
+
+ % Setup outports
+ DAQmxWriteDigitalLines(lib,mytaskh.DO_CS_INV,...
+ numSampsPerChan,timeout,dataLayout,1);
+ DAQmxWriteDigitalLines(lib,mytaskh.DO_SCLK,...
+ numSampsPerChan,timeout,dataLayout,0);
+ DAQmxWriteDigitalLines(lib,mytaskh.DO_DIN,...
+ numSampsPerChan,timeout,dataLayout,0);
+ DAQmxWriteDigitalLines(lib,mytaskh.DO_CS_INV,...
+ numSampsPerChan,timeout,dataLayout,0);
+
+ % Send controll byte : "100x1110", där x är kontrollbiten.
+ set_ADC_bit(1);
+ set_ADC_bit(0);
+ set_ADC_bit(0);
+ set_ADC_bit(control_bit);
+ set_ADC_bit(1);
+ set_ADC_bit(1);
+ set_ADC_bit(1);
+ set_ADC_bit(0);
+
+ pause(0.005)
+
+ DAQmxWriteDigitalLines(lib,mytaskh.DO_SCLK,...
+ numSampsPerChan,timeout,dataLayout,1);
+
+ ADC = zeros(1,12);
+ for i=1:12
+ ADC(13-i) = get_ADC_bit();
+ end
+ get_ADC_bit();
+ get_ADC_bit();
+ get_ADC_bit();
+ get_ADC_bit();
+ DAQmxWriteDigitalLines(lib,mytaskh.DO_CS_INV,...
+ numSampsPerChan,timeout,dataLayout,1);
+
+ x1=ADC(12)*128+ADC(11)*64+ADC(10)*32+ADC(9)*16+ADC(8)*8+ADC(7)*4+ADC(6)*2+ADC(5)*1-128;
+ manual_speed = min(max(x1,0),127);
+ otherwise
+ disp('Wrong number of arguments sent to get_manual_speed(track)! Should be 1!');
+end
+end
+
+function [] = set_ADC_bit(valueDO)
+global mytaskh
+global lib
+
+DAQmx_Val_ChanPerLine =0; % One Channel For Each Line
+DAQmx_Val_ChanForAllLines =1; % One Channel For All Lines
+DAQmx_Val_GroupByChannel = 0; % Group by Channel
+DAQmx_Val_GroupByScanNumber =1; % Group by Scan Number
+
+numSampsPerChan = 1;
+timeout = 1;
+dataLayout = DAQmx_Val_GroupByChannel; % Group by Channel
+% dataLayout = DAQmx_Val_GroupByScanNumber; % Group by Scan Number
+
+DAQmxWriteDigitalLines(lib,mytaskh.DO_DIN,...
+ numSampsPerChan,timeout,dataLayout,valueDO);
+
+DAQmxWriteDigitalLines(lib,mytaskh.DO_SCLK,...
+ numSampsPerChan,timeout,dataLayout,1);
+DAQmxWriteDigitalLines(lib,mytaskh.DO_SCLK,...
+ numSampsPerChan,timeout,dataLayout,0);
+end
+
+function [valueDI] = get_ADC_bit()
+global mytaskh
+global lib
+
+DAQmx_Val_ChanPerLine =0; % One Channel For Each Line
+DAQmx_Val_ChanForAllLines =1; % One Channel For All Lines
+DAQmx_Val_GroupByChannel = 0; % Group by Channel
+DAQmx_Val_GroupByScanNumber =1; % Group by Scan Number
+
+numSampsPerChan = 1;
+timeout = 1;
+fillMode = DAQmx_Val_GroupByChannel; % Group by Channel
+% fillMode = DAQmx_Val_GroupByScanNumber; % Group by Scan Number
+dataLayout = DAQmx_Val_GroupByChannel; % Group by Channel
+% dataLayout = DAQmx_Val_GroupByScanNumber; % Group by Scan Number
+numchanDI = 1; % DI lines
+numsample = 1;
+
+DAQmxWriteDigitalLines(lib,mytaskh.DO_SCLK,...
+ numSampsPerChan,timeout,dataLayout,0);
+DAQmxWriteDigitalLines(lib,mytaskh.DO_SCLK,...
+ numSampsPerChan,timeout,dataLayout,1);
+valueDI = DAQmxReadDigitalLines(lib,mytaskh.DI_DOUT,numSampsPerChan,timeout,fillMode,numchanDI,numsample);
+end
+
+function sampsPerChanWritten = DAQmxWriteDigitalLines(lib,taskh,numSampsPerChan,timeout,dataLayout,DOvalue)
+% function sampsPerChanWritten = DAQmxWriteDigitalLines(lib,taskh,numSampsPerChan,timeout,dataLayout,DOvalue)
+%
+% this function writes digital outputs from previously setup task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% taskh - taskhandle of analog inputs
+% numSampsPerChan = ?
+% timeout - in seconds
+% dataLayout - DAQmx_Val_GroupByChannel or DAQmx_Val_GroupByScanNumber
+% DOvalue - value to write (0 or 1)
+% 1 channel example: 0
+% 2 channel example: [0,0]
+%
+% C functions:
+% int32 DAQmxReadDigitalLines (
+% TaskHandle taskHandle,int32 numSampsPerChan,float64 timeout,bool32 fillMode,
+% uInt8 readArray[],uInt32 arraySizeInBytes,int32 *sampsPerChanRead,int32 *numBytesPerSamp,bool32 *reserved);
+% int32 DAQmxStopTask (TaskHandle taskHandle);
+% int32 DAQmxWriteDigitalLines (
+% TaskHandle taskHandle,int32 numSampsPerChan,bool32 autoStart,float64 timeout,bool32 dataLayout,
+% uInt8 writeArray[],int32 *sampsPerChanWritten,bool32 *reserved);
+% int32 DAQmxStopTask (TaskHandle taskHandle);
+%
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+autoStart = 1;
+
+
+[err,sampsPerChanWritten,empty] = calllib(lib,'DAQmxWriteDigitalLines',...
+ taskh,numSampsPerChan,autoStart,timeout,dataLayout,...
+ DOvalue,0,[]);
+DAQmxCheckError(lib,err);
+end
+
+function data = DAQmxReadDigitalLines(lib,taskh,numSampsPerChan,timeout,fillMode,numchan,numsample)
+% function data = DAQmxReadDigitalLines(lib,taskh,numSampsPerChan,timeout,fillMode,numchan,numsample)
+%
+% this function reads digital inputs from previously setup task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% taskh - taskhandle of analog inputs
+% numSampsPerChan = ?
+% timeout - in seconds
+% fillMode - DAQmx_Val_GroupByChannel or DAQmx_Val_GroupByScanNumber
+% numchan - number of digital channels to read
+% numsample - number of samples to read
+%
+% C functions:
+% int32 DAQmxReadDigitalLines (
+% TaskHandle taskHandle,int32 numSampsPerChan,float64 timeout,bool32 fillMode,
+% uInt8 readArray[],uInt32 arraySizeInBytes,int32 *sampsPerChanRead,int32 *numBytesPerSamp,bool32 *reserved);
+% int32 DAQmxStopTask (TaskHandle taskHandle);
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+
+% make some pointers
+% readarray1=ones(numchan,numsample); readarray1_ptr=libpointer('doublePtr',readarray1);
+readarray1=ones(numchan,numsample); readarray1_ptr=libpointer('uint8Ptr',readarray1);
+sampread=1; sampread_ptr=libpointer('int32Ptr',sampread);
+bytespersamp=1; bytespersamp_ptr=libpointer('int32Ptr',bytespersamp);
+empty=[]; empty_ptr=libpointer('uint32Ptr',empty);
+
+arraylength=numsample*numchan; % more like 'buffersize'
+
+[err,~,sampread,~,empty]=calllib(lib,'DAQmxReadDigitalLines',...
+ taskh,numSampsPerChan,timeout,fillMode,...
+ readarray1_ptr,arraylength,sampread_ptr,bytespersamp_ptr,empty_ptr);
+DAQmxCheckError(lib,err);
+
+% err = calllib(lib,'DAQmxStopTask',taskh);
+% DAQmxCheckError(lib,err);
+
+data = sampread;
+end
+
+function DAQmxCheckError(lib,err)
+% function DAQmxCheckError(lib,err)
+%
+% read error code
+% zero means no error - does nothing
+% nonzero - find out error string and generate error
+%
+% inputs:
+% lib = .dll or alias (ex. 'myni')
+% err = DAQmx error
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+if err ~= 0
+ % find out how long the error string is
+ [numerr,~] = calllib(lib,'DAQmxGetErrorString',err,'',0);
+
+ % get error string
+ errstr = char(1:numerr); % have to pass dummy string of correct length
+ [~,errstr] = calllib(lib,'DAQmxGetErrorString',err,errstr,numerr);
+
+ % matlab error
+ error(['DAQmx error - ',errstr])
+end
+end \ No newline at end of file
diff --git a/Kod/bilbana/IOFunctions/initialize_counters.m b/Kod/bilbana/IOFunctions/initialize_counters.m
new file mode 100644
index 0000000..27e76ac
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/initialize_counters.m
@@ -0,0 +1,217 @@
+function [] = initialize_counters(track)
+%INITIALIZE_COUNTERS Creates counter tasks by calling the new driver NIDAQmx.
+%
+% There are one task associated with each counter. The handles of these
+% tasks are stored in global struct mytaskh. The tasks are not started
+% by this function, the user needs to call set_car_speed and/or
+% start_race to arm any counters.
+%
+% Track 1/track 2:
+% ctr_0/ctr_4 - Pulse train signal, representing car speed.
+% ctr_1/ctr_5 - Check point counter.
+% ctr_2/ctr_6 - Lap counter.
+% ctr_3/ctr_7 - Time counter, counts at 100kHz.
+%
+% Tobias Lindell - 2013-02-12
+
+global mytaskh
+global lib
+
+switch nargin
+ case 1
+ lib = 'myni'; % library alias
+ if ~libisloaded(lib)
+ disp('Matlab: Loading nicaiu.dll. Please wait!')
+ funclist = loadlibrary('c:\windows\system32\nicaiu.dll','C:\Program Files (x86)\National Instruments\Shared\ExternalCompilerSupport\C\include\nidaqmx.h','alias',lib); %#ok<NASGU>
+ %if you do NOT have nicaiu.dll and nidaqmx.h
+ %in your Matlab path,add full pathnames or copy the files.
+ %libfunctions(lib,'-full') % use this to show the...
+ %libfunctionsview(lib) % included function
+ disp('Matlab: Nicaiu.dll loaded!')
+ end
+
+ disp(['Initializing track ',num2str(track),' please wait!'])
+
+ %%% NIconstants
+ DAQmx_Val_Hz = 10373; % Hz
+
+ % DAQmx_Val_High = 10192; % High
+ DAQmx_Val_Low = 10214; % Low
+
+ % DAQmx_Val_FiniteSamps = 10178; % Finite Samples
+ DAQmx_Val_ContSamps = 10123; % Continuous Samples
+ % DAQmx_Val_HWTimedSinglePoint = 12522; % Hardware Timed Single Point
+
+ DAQmx_Val_Rising = 10280; % Rising
+ % DAQmx_Val_Falling = 10171; % Falling
+
+ DAQmx_Val_CountUp = 10128; % Count Up
+ % DAQmx_Val_CountDown = 10124; % Count Down
+ % DAQmx_Val_ExtControlled = 10326; % Externally Controlled
+
+
+
+ % Track 1
+ switch track
+ case 1
+ %%% Car speed counter
+ mytaskh.ctr_0 = DAQmxCreateCOPulseChanFreq(lib,'Dev1/ctr0',DAQmx_Val_Hz,DAQmx_Val_Low,2.5e-08,100,0.001);
+ calllib(lib,'DAQmxCfgImplicitTiming',mytaskh.ctr_0,DAQmx_Val_ContSamps,1000);
+
+ %%% Sensor counters
+
+ % Check points
+ % Starting count edges counter, detecting rising edges
+ mytaskh.ctr_1 = DAQmxCreateCICountEdgesChan(lib,'Dev1/ctr1',DAQmx_Val_Rising,DAQmx_Val_CountUp);
+ % Setting up terminal and filter
+ calllib(lib,'DAQmxSetCICountEdgesTerm',mytaskh.ctr_1,'Dev1/ctr1','PFI35');
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrEnable',mytaskh.ctr_1,'Dev1/ctr1',1);
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrMinPulseWidth',mytaskh.ctr_1,'Dev1/ctr1',5e-6);
+
+ % Lap counter
+ mytaskh.ctr_2 = DAQmxCreateCICountEdgesChan(lib,'Dev1/ctr2',DAQmx_Val_Rising,DAQmx_Val_CountUp);
+ calllib(lib,'DAQmxSetCICountEdgesTerm',mytaskh.ctr_2,'Dev1/ctr2','PFI31');
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrEnable',mytaskh.ctr_2,'Dev1/ctr2',1);
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrMinPulseWidth',mytaskh.ctr_2,'Dev1/ctr2',5e-6);
+
+ %%% Timer counter
+ mytaskh.ctr_3 = DAQmxCreateCICountEdgesChan(lib,'Dev1/ctr3',DAQmx_Val_Rising,DAQmx_Val_CountUp);
+ calllib(lib,'DAQmxSetCICountEdgesTerm',mytaskh.ctr_3,'Dev1/ctr3','/Dev1/100kHzTimebase');
+
+ case 2
+ %%% Car speed counter
+ mytaskh.ctr_4 = DAQmxCreateCOPulseChanFreq(lib,'Dev1/ctr4',DAQmx_Val_Hz,DAQmx_Val_Low,2.5e-08,100,0.001);
+ calllib(lib,'DAQmxCfgImplicitTiming',mytaskh.ctr_4,DAQmx_Val_ContSamps,1000);
+
+ %%% Sensor counters
+ % Check points
+ mytaskh.ctr_5 = DAQmxCreateCICountEdgesChan(lib,'Dev1/ctr5',DAQmx_Val_Rising,DAQmx_Val_CountUp);
+ calllib(lib,'DAQmxSetCICountEdgesTerm',mytaskh.ctr_5,'Dev1/ctr5','PFI19');
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrEnable',mytaskh.ctr_5,'Dev1/ctr5',1);
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrMinPulseWidth',mytaskh.ctr_5,'Dev1/ctr5',5e-6);
+
+ % Lap counter
+ mytaskh.ctr_6 = DAQmxCreateCICountEdgesChan(lib,'Dev1/ctr6',DAQmx_Val_Rising,DAQmx_Val_CountUp);
+ calllib(lib,'DAQmxSetCICountEdgesTerm',mytaskh.ctr_6,'Dev1/ctr6','PFI15');
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrEnable',mytaskh.ctr_6,'Dev1/ctr6',1);
+ calllib(lib,'DAQmxSetCICountEdgesDigFltrMinPulseWidth',mytaskh.ctr_6,'Dev1/ctr6',5e-6);
+
+ %%% Timer counter
+ mytaskh.ctr_7 = DAQmxCreateCICountEdgesChan(lib,'Dev1/ctr7',DAQmx_Val_Rising,DAQmx_Val_CountUp);
+ calllib(lib,'DAQmxSetCICountEdgesTerm',mytaskh.ctr_7,'Dev1/ctr7','/Dev1/100kHzTimebase');
+
+ otherwise
+ disp('Wrong track number sent to initialize_counters!')
+ return
+ end
+ disp(['Track ',num2str(track),' initialized!'])
+ otherwise
+ disp('Wrong number of input arguments sent to initialize_counters(track)! Should be 1!')
+end
+end
+
+function DAQmxCheckError(lib,err)
+% function DAQmxCheckError(lib,err)
+%
+% read error code
+% zero means no error - does nothing
+% nonzero - find out error string and generate error
+%
+% inputs:
+% lib = .dll or alias (ex. 'myni')
+% err = DAQmx error
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+if err ~= 0
+ % find out how long the error string is
+ [numerr,~] = calllib(lib,'DAQmxGetErrorString',err,'',0);
+
+ % get error string
+ errstr = char(1:numerr); % have to pass dummy string of correct length
+ [~,errstr] = calllib(lib,'DAQmxGetErrorString',err,errstr,numerr);
+
+ % matlab error
+ error(['DAQmx error - ',errstr])
+end
+end
+
+function taskh = DAQmxCreateCICountEdgesChan(lib,ctrs,edge,direction)
+% function taskh = DAQmxCreateCICountEdgesChan(lib,ctrs,edge,direction)
+%
+% this function creates a task and adds counter input channel(s) to the task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% ctrs - channel(s) to add to task
+% 1 channel example: 'Dev1/ctr0'
+% 2 channels example: {'Dev1/ctr0','Dev1/ctr1'}
+% passing as .../ctr0-1 probably also works, but I didn't test
+% edge - which edge that is detected/counted ('rising' or 'falling')
+% direction - direction to count ('increment' or 'decrement')
+%
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+taskh = [];
+name_task = ''; % recommended to avoid problems
+[err,~,taskh] = calllib(lib,'DAQmxCreateTask',name_task,uint32(taskh));
+DAQmxCheckError(lib,err);
+
+name_line = ''; % recommended to avoid problems
+[err,~,~,~] = calllib(lib,'DAQmxCreateCICountEdgesChan',taskh,ctrs,name_line,edge,0,direction);
+DAQmxCheckError(lib,err);
+
+% verify everything OK
+DAQmx_Val_Task_Verify = 2; % Verify
+[err,~] = calllib(lib,'DAQmxTaskControl',taskh,DAQmx_Val_Task_Verify);
+DAQmxCheckError(lib,err);
+
+end
+
+function taskh = DAQmxCreateCOPulseChanFreq(lib,ctrs,units,idleState,initialDelay,freq,dutyCycle)
+% function taskh = DAQmxCreateCOPulseChanFreq(lib,ctrs,units,idleState,initialDelay,freq,dutyCycle)
+%
+% this function creates a task and adds counter input channel(s) to the task
+%
+% inputs:
+% lib - .dll or alias (ex. 'myni')
+% ctrs - channel(s) to add to task
+% 1 channel example: 'Dev1/ctr0'
+% 2 channels example: {'Dev1/ctr0','Dev1/ctr1'}
+% passing as .../ctr0-1 probably also works, but I didn't test
+% units - The units in which to specify freq. (DAQmx_Val_Hz = hertz)
+% idleState - The resting state of the output terminal.
+% DAQmx_Val_High - High state.
+% DAQmx_Val_Low - Low state.
+% initialDelay - The amount of time in seconds to wait before generating the first pulse.
+% freq - The frequency at which to generate pulses.
+% dutyCycle - The width of the pulse divided by the pulse period.
+%
+%
+% written by Tobias Lindell
+% inspired by Nathan Tomlin (nathan.a.tomlin@gmail.com)
+% v0 - 1302
+
+
+taskh = [];
+name_task = ''; % recommended to avoid problems
+[err,~,taskh] = calllib(lib,'DAQmxCreateTask',name_task,uint32(taskh));
+DAQmxCheckError(lib,err);
+
+name_line = ''; % recommended to avoid problems
+[err,~,~,~] = calllib(lib,'DAQmxCreateCOPulseChanFreq',taskh,ctrs,name_line,units,idleState,initialDelay,freq,dutyCycle);
+DAQmxCheckError(lib,err);
+
+% verify everything OK
+DAQmx_Val_Task_Verify = 2; % Verify
+[err,~] = calllib(lib,'DAQmxTaskControl',taskh,DAQmx_Val_Task_Verify);
+DAQmxCheckError(lib,err);
+
+end
+
+
diff --git a/Kod/bilbana/IOFunctions/set_car_speed.m b/Kod/bilbana/IOFunctions/set_car_speed.m
new file mode 100644
index 0000000..3aab1db
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/set_car_speed.m
@@ -0,0 +1,56 @@
+function [] = set_car_speed(track,speed)
+%SET_CAR_SPEED Sets the specified car (track) to a specified speed.
+% Changes the duty cycle of counter 0 and 4 to change speed of car on
+% track 1 and track 2 respectively. Valid values of the duty cycle are
+% between 0 and 1, the input speed of the cars are defined as percent.
+%
+% Tobias Lindell 2013-02-12.
+
+global mytaskh
+global lib
+
+switch nargin
+ case 2
+ % Check if _any_ counters been initilized, stop program if not
+ if isempty(mytaskh)
+ disp(['User needs to initialize counters for track ',num2str(track),' before setting car speed!'])
+ clearvars -global mytaskh lib
+ return
+ end
+
+ % Setting duty cycle, with limits
+ speed = min(99, speed);
+ speed = max(0.1,speed);
+ duty_cycle = speed / 100;
+
+ switch track
+ case 1
+ % Check if track 1 counter has been initialized, stop program if not
+ if isfield(mytaskh,'ctr_0')
+ % Stop task (necessary to change duty cycle)
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_0);
+ % Set new duty cycle
+ calllib(lib,'DAQmxSetCOPulseDutyCyc',mytaskh.ctr_0,'Dev1/ctr0',duty_cycle);
+ % Restart task
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_0);
+ else
+ disp(['User needs to initialize counters for track ',num2str(track),' before setting car speed!'])
+ return
+ end
+ case 2
+ if isfield(mytaskh,'ctr_4')
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_4);
+ calllib(lib,'DAQmxSetCOPulseDutyCyc',mytaskh.ctr_4,'Dev1/ctr4',duty_cycle);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_4);
+ else
+ disp(['User needs to initialize counters for track ',num2str(track),' before setting car speed!'])
+ return
+ end
+ otherwise
+ disp('Wrong track number sent to set_car_speed!')
+ return
+ end
+ otherwise
+ disp('Wrong number of arguments sent to set_car_speed(track,speed)! Should be 2!')
+end
+end
diff --git a/Kod/bilbana/IOFunctions/start_race.m b/Kod/bilbana/IOFunctions/start_race.m
new file mode 100644
index 0000000..5e51017
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/start_race.m
@@ -0,0 +1,56 @@
+function [] = start_race(track)
+%START_RACE Stops, resets and starts all counters associated with specified
+%track.
+% All counters, except the pulse train speed counters, associated with a
+% specified track are stopped and restarted. This resets the current
+% values of the counters to the initial value (0 for all counters).
+%
+% At first call the counters just starts, the extra stopping of counters
+% that are not running does nothing.
+%
+% Tobias Lindell - 2013-02-12
+
+global mytaskh
+global lib
+
+switch nargin
+ case 1
+ % Check if _any_ counters been initilized, stop program if not
+ if isempty(mytaskh)
+ disp(['User needs to initialize counters for track ',num2str(track),' before setting car speed!'])
+ clearvars -global mytaskh lib
+ return
+ end
+
+ switch track
+ case 1
+ if ~isfield(mytaskh,'ctr_1')
+ disp(['User needs to initialize counters for track ',num2str(track),' before setting car speed!'])
+ return
+ end
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_1);
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_2);
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_3);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_1);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_2);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_3);
+ case 2
+ if ~isfield(mytaskh,'ctr_5')
+ disp(['User needs to initialize counters for track ',num2str(track),' before setting car speed!'])
+ return
+ end
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_5);
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_6);
+ calllib(lib,'DAQmxStopTask',mytaskh.ctr_7);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_5);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_6);
+ calllib(lib,'DAQmxStartTask',mytaskh.ctr_7);
+ otherwise
+ disp('Wrong track number sent to start_race!')
+ return
+ end
+ otherwise
+ disp('Wrong number of arguments sent to start_race(track)! Should be 1!')
+end
+end
+
diff --git a/Kod/bilbana/IOFunctions/terminate.m b/Kod/bilbana/IOFunctions/terminate.m
new file mode 100644
index 0000000..26a43f2
--- /dev/null
+++ b/Kod/bilbana/IOFunctions/terminate.m
@@ -0,0 +1,83 @@
+function [] = terminate(track)
+%TERMINATE Stops all counters associated with specified track.
+% Stops all counters associated with a specified track, and clears the
+% resources.
+%
+% If both tracks are terminated as a result of a call on terminate() all
+% resources, including the global variables, will be cleared and the
+% PCI6602 card will be reset to original state.
+%
+% Tobias Lindell 2013-02-12
+
+global mytaskh
+global lib
+
+switch nargin
+ case 1
+ if isempty(mytaskh)
+ disp('User needs to initialize counters before terminating!')
+ clearvars -global mytaskh lib
+ return
+ end
+
+
+ switch track
+ case 1
+ % Check if track 1 counter has been initialized, stop program if not
+ if isfield(mytaskh,'ctr_0')
+ % Clear counters of selcted track
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_0);
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_1);
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_2);
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_3);
+ clear mytaskh.ctr_0
+ clear mytaskh.ctr_1
+ clear mytaskh.ctr_2
+ clear mytaskh.ctr_3
+ mytaskh = rmfield(mytaskh,'ctr_0');
+ mytaskh = rmfield(mytaskh,'ctr_1');
+ mytaskh = rmfield(mytaskh,'ctr_2');
+ mytaskh = rmfield(mytaskh,'ctr_3');
+ % Check to see if counters of other track are cleared, if so
+ % reset card to original state and clear global variables
+ if ~isfield(mytaskh,'ctr_4')
+ disp('Everything terminated. Device will reset!')
+ calllib(lib,'DAQmxResetDevice','Dev1');
+ clearvars -global mytaskh lib
+ end
+
+ else
+ disp(['User needs to initialize counters for track ',num2str(track),' before terminating!'])
+ return
+ end
+ case 2
+ if isfield(mytaskh,'ctr_4')
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_4);
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_5);
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_6);
+ calllib(lib,'DAQmxClearTask',mytaskh.ctr_7);
+ clear mytaskh.ctr_4
+ clear mytaskh.ctr_5
+ clear mytaskh.ctr_6
+ clear mytaskh.ctr_7
+ mytaskh = rmfield(mytaskh,'ctr_4');
+ mytaskh = rmfield(mytaskh,'ctr_5');
+ mytaskh = rmfield(mytaskh,'ctr_6');
+ mytaskh = rmfield(mytaskh,'ctr_7');
+ if ~isfield(mytaskh,'ctr_0')
+ disp('Everything terminated. Device will reset!')
+ calllib(lib,'DAQmxResetDevice','Dev1');
+ clearvars -global mytaskh lib
+ end
+ else
+ disp(['User needs to initialize counters for track ',num2str(track),' before terminating!'])
+ return
+ end
+ otherwise
+ disp('Wrong track argument sent to terminate(track)! Should be 1 or 2!')
+ end
+ otherwise
+ disp('Wrong number of arguments sent to terminate(track)! Should be 1!')
+end
+end
+
diff --git a/Kod/bilbana/run_scalectrix.m b/Kod/bilbana/run_scalectrix.m
new file mode 100644
index 0000000..8ef6f47
--- /dev/null
+++ b/Kod/bilbana/run_scalectrix.m
@@ -0,0 +1,47 @@
+function [] = run_scalectrix()
+% Runs the Scalectrix with hand controls enabled. "q" stops execution.
+%
+% Tobias Lindell - 2013-02-12
+
+
+disp('Startar bilbanan. Avsluta med q')
+hf=figure('position',[0 0 eps eps],'menubar','none');
+
+%% Init race track
+initialize_counters(1)
+initialize_counters(2)
+
+config_IOs
+
+start_race(1)
+start_race(2)
+
+%% Running loop
+while 1
+% tic
+ % Check if user has pressed q
+ if strcmp(get(hf,'currentcharacter'),'q')
+ close(hf)
+ break
+ end
+ % force the event queue to flush
+ figure(hf)
+ drawnow
+
+ % Read speed from controllers and set new car speeds
+ my_speed_1 = get_manual_speed(1);
+ my_speed_1 = 100*((55 - my_speed_1)/55);
+ set_car_speed(1,my_speed_1);
+
+ my_speed_2 = get_manual_speed(2);
+ my_speed_2 = 100*((55 - my_speed_2)/55);
+ set_car_speed(2,my_speed_2)
+% toc
+ pause(0.1) % Pause 0.1 s
+end
+
+[lap_car1,chk_pnt_car1,time] = get_car_position(1)
+[lap_car2,chk_pnt_car2,time] = get_car_position(2)
+
+terminate(1)
+terminate(2) \ No newline at end of file
diff --git a/Kod/bilbana/studentFunctions/car_controller.m b/Kod/bilbana/studentFunctions/car_controller.m
new file mode 100644
index 0000000..069e8f5
--- /dev/null
+++ b/Kod/bilbana/studentFunctions/car_controller.m
@@ -0,0 +1,16 @@
+function car = car_controller(car_in)
+
+car = car_in;
+
+% Read sensors
+[car, cp_passed] = update_position(car);
+
+if cp_passed
+ % Update speed
+
+ new_control = car.control(end) + 0.5*(rand() - 0.5); % Temporary control policy
+
+ car = update_control(new_control, car);
+end
+
+end \ No newline at end of file
diff --git a/Kod/bilbana/studentFunctions/init_car.m b/Kod/bilbana/studentFunctions/init_car.m
new file mode 100644
index 0000000..8206206
--- /dev/null
+++ b/Kod/bilbana/studentFunctions/init_car.m
@@ -0,0 +1,25 @@
+function car = init_car(track_number)
+
+car = struct();
+
+% Car state
+car.state = 'intro';
+
+% Track number
+car.track_number = track_number;
+
+% Current track segment
+car.position = 0;
+
+% Current lap
+car.lap = 0;
+
+% Start race timer
+car.t0 = tic();
+
+% Control signal
+car.control = nan(1,1);
+car.control_log_time = nan(1,1);
+car.control_log_position = zeros(1,1);
+
+end \ No newline at end of file
diff --git a/Kod/bilbana/studentFunctions/plot_results.m b/Kod/bilbana/studentFunctions/plot_results.m
new file mode 100644
index 0000000..34ea2e4
--- /dev/null
+++ b/Kod/bilbana/studentFunctions/plot_results.m
@@ -0,0 +1,15 @@
+% Plot the results
+figure(100)
+subplot(2,1,1)
+stairs(car.control_log_time, car.control, 'LineWidth', 2) % Gör en trappstegsplot
+xlabel('Time [s]')
+ylabel('Control signal [%]')
+title('Control signal trajectory')
+grid on
+
+subplot(2,1,2)
+stairs(car.control_log_time, car.control_log_position, 'r', 'LineWidth', 2)
+xlabel('Time [s]')
+ylabel('Car position [segment number]')
+title('Car position')
+grid on
diff --git a/Kod/bilbana/studentFunctions/run_simple_example.m b/Kod/bilbana/studentFunctions/run_simple_example.m
new file mode 100644
index 0000000..45794f0
--- /dev/null
+++ b/Kod/bilbana/studentFunctions/run_simple_example.m
@@ -0,0 +1,41 @@
+%% ---------------- Do not touch ---------------- %
+disp('Startar bilbanan. Avsluta med q')
+hf=figure('position',[0 0 eps eps],'menubar','none');
+% ----------------------------------------------- %
+%% User input
+track_number = 1;
+car = init_car(track_number);
+
+%% Init race track
+initialize_counters(car.track_number)
+config_IOs
+start_race(car.track_number)
+
+%% Start cars
+start_control = 29; % 29 works for the white castrol car marked with number 82
+car = update_control(start_control, car);
+
+%% Running loop
+while 1
+
+ % ---------------- Do not touch ---------------- %
+ % Check if user has pressed q
+ if strcmp(get(hf,'currentcharacter'),'q')
+ close(hf)
+ break
+ end
+ % force the event queue to flush
+ figure(hf)
+ drawnow
+ % ---------------------------------------------- %
+
+ car = car_controller(car);
+
+ pause(0.1) % Pause 0.1 s
+end
+
+terminate(1)
+terminate(2)
+
+% run file to plot results
+plot_results(); \ No newline at end of file
diff --git a/Kod/bilbana/studentFunctions/update_control.m b/Kod/bilbana/studentFunctions/update_control.m
new file mode 100644
index 0000000..ee6599c
--- /dev/null
+++ b/Kod/bilbana/studentFunctions/update_control.m
@@ -0,0 +1,16 @@
+function car = update_control(new_control_signal, car_in)
+
+% Return track struct
+car = car_in;
+
+% Update track struct
+car.control(end+1) = new_control_signal;
+car.control_log_time(end+1) = toc(car.t0);
+car.control_log_position(end+1) = car.position;
+
+% Update speed
+set_car_speed(car.track_number, car.control(end));
+
+end
+
+
diff --git a/Kod/bilbana/studentFunctions/update_position.m b/Kod/bilbana/studentFunctions/update_position.m
new file mode 100644
index 0000000..dfca55f
--- /dev/null
+++ b/Kod/bilbana/studentFunctions/update_position.m
@@ -0,0 +1,39 @@
+function [car, gateway_passed] = update_position(car_in)
+
+car = car_in;
+
+[lap_car, chk_pnt, time] = get_car_position(car.track_number);
+
+if lap_car == true
+ % New lap
+
+ % Update position on track
+ car.position = 1;
+
+ % Add lap to lap counter
+ car.lap = car.lap + 1;
+
+ % Update gw passed
+ gateway_passed = true;
+
+ % Make sound
+ beep;
+
+elseif chk_pnt == true && car.position ~= 0
+ % CP passed
+
+ % Update position
+ car.position = car.position + 1;
+
+ % update gw passed
+ gateway_passed = true;
+
+ % Make sound
+ beep;
+
+else
+ gateway_passed = false;
+
+end
+
+end \ No newline at end of file