global SIMULATION; SIMULATION = 0; % Paramètres de lecture DIRNAME = "/home/geoffrey/CdF/cdf2018-principal/log/"; FILENAME = "last.csv"; PATH = DIRNAME + FILENAME; % Paramètres de simulation global SIMULATION_TIME SIMULATION_DT; SIMULATION_TIME = 10; SIMULATION_DT = 1e-15; %BEGIN DIMENSIONS % Dimensions pistes global pisteWidth pisteHeight pisteOrigX pisteOrigY; pisteWidth = 3000.0; pisteHeight = 2000.0; pisteOrigX = 0.0; pisteOrigY = 0.0; % Dimensions robot global width height distanceBetweenWheels wheelDiameter wheelPerimeter motorSpeedGainRPMpV motorSpeedGain motorNominalTension motorControllerAlimentation motorControllerReference motorSaturationMin motorSaturationMax pwmMax coderResolution coderDataFactor coderDataResolution cranReducOut cranReducIn reducRatio coderFullResolution avPerCycle; width = 250.0; % mm (from meca) height = 100.0; % mm (from random) distanceBetweenWheels = width; % mm (from meca) wheelDiameter = 80.0; % mm (from meca) wheelPerimeter = (wheelDiameter * pi); % mm motorSpeedGainRPMpV = 233.0; % rpm/V (from datasheet) motorSpeedGain = (motorSpeedGainRPMpV / 60.0); % motor rev/s/V motorNominalTension = 24.0; % V (from datasheet) motorControllerAlimentation = 24.0; % V (from elec) motorControllerReference = 5.0; % V (from wiring) motorSaturationMin = 0.0; % V (from random) motorSaturationMax = 4.0; % V (from testing) pwmMax = 3.3; % V (from FPGA datasheet) coderResolution = 370.0; % cycles/motor rev coderDataFactor = 4.0; % increments/motor cycles coderDataResolution = (coderResolution * coderDataFactor); % cycles/motor rev cranReducOut = 48.0; % nb crans (from meca) cranReducIn = 12.0; % nb crans (from meca) reducRatio = (cranReducIn / cranReducOut); % reduction ratio coderFullResolution = (coderDataResolution / reducRatio); % cycles / wheel rev avPerCycle = (wheelPerimeter / coderFullResolution); % mm % Pour éviter les pics de codeuse liées à la communication I2C absoluteMaxVitesseRobot = 10.0; % km/h absoluteMaxVitesseRobotMMpS = (absoluteMaxVitesseRobot * 10000.0 / 36.0); % mm/s absoluteMaxVitesseRobotRevpS = (absoluteMaxVitesseRobotMMpS / wheelPerimeter); % rev/s absoluteMaxVitesseRobotCycpS = (absoluteMaxVitesseRobotRevpS * coderFullResolution); % cycle/s % Constantes asservissement global dDirEcartMin dDirEcartMax oDirEcartMin oDirEcartMax oEcartMin oEcartMax targetTensionRatio targetTension carotteDistance dKP dKI dKD oKP oKI oKD margeSecurite; % Asservissement en distance dDirEcartMin = 30.0; % mm dDirEcartMax = 50.0; % mm dKP = 0.05; dKI = 0.0; dKD = 0.0; targetTensionRatio = 0.75; targetTension = (targetTensionRatio * motorSaturationMax); % V carotteDistance = (targetTension / dKP); % mm % Asservissement en angle oDirEcartMin = (25.0 / 360.0 * 2.0 * pi); % rad oDirEcartMax = (45.0 / 360.0 * 2.0 * pi); % rad oEcartMin = (25.0 / 360.0 * 2.0 * pi); % rad oEcartMax = (45.0 / 360.0 * 2.0 * pi); % rad oKP = (motorSaturationMax / (wheelPerimeter * pi)); % au max peut dérivier de pi oKI = 0.0; oKD = 0.0; carotteAngle = (targetTension / oKP); % mm margeSecurite = 300.0; % mm %END DIMENSIONS global s; if SIMULATION == 1 % Génération de la consigne xinit = 50; yinit = 50; oinit = 4 * pi; d1t = 2; d1x = -300; d1y = 0; d1o = 2 * pi; dt = SIMULATION_DT; global xcons ycons ocons; xcons = timeseries([xinit, xinit, d1x, d1x], [0 d1t-dt d1t SIMULATION_TIME]); ycons = timeseries([yinit, yinit, d1y, d1y], [0 d1t-dt d1t SIMULATION_TIME]); ocons = timeseries([oinit, oinit, d1o, d1o], [0 d1t-dt d1t SIMULATION_TIME]); % Simulation disp("Lancement de la simulation"); s = sim("modelisation", "StopTime", string(SIMULATION_TIME), "MinStep", string(SIMULATION_DT)); fprintf("Simulation sampling rate: %f Hz\n", length(s.tout)/SIMULATION_TIME); else disp("Ouverture des données"); T = readtable(PATH); % Données pratiques → données théoriques T.time(1) = 0; T.x = T.xConnu; T.y = T.yConnu; T.o = T.oConnu; T.secBackL = -T.secBackL; T.secBackR = -T.secBackR; disp("Enregistrement des données"); s = containers.Map; for name=T.Properties.VariableNames nameChar = char(name); s(nameChar) = timeseries(T.(nameChar), T.time); end % Modification pour faire passer comme une simu td = getTimePoints(); SIMULATION_TIME = td(end); end % Graphes clf global p; % Évolution spatiale subplot(2, 3, 1); initGraph updateToTime(SIMULATION_DT); % Codeuses p = subplot(2, 3, 3); hold on; timeGraph(["lCodTot", "rCodTot", "newL", "newR"]); addLimitline(p, 2^16-1); addLimitline(p, 0); title("Codeuses"); xlabel("Temps (s)"); ylabel("Crans"); legend("Total gauche", "Total droite", "Brut gauche", "Brut droite"); % Roues p = subplot(2, 3, 2); hold on; timeGraph(["lVolt", "rVolt", "dVolt", "oVolt"]); addLimitline(p, -motorSaturationMin); addLimitline(p, -motorSaturationMax); addLimitline(p, motorSaturationMin); addLimitline(p, motorSaturationMax); addLimitline(p, 0); title("Roues"); xlabel("Temps (s)"); ylabel("Tension (V)"); legend("Tension gauche", "Tension droite", "Dont distance", "Dont direction"); % Distance p = subplot(2, 3, 4); hold on; timeGraph(["dDirEcart", "dEcart", "oErr"]); addLimitline(p, 0); addLimitline(p, dDirEcartMin); addLimitline(p, dDirEcartMax); addLimitline(p, -dDirEcartMin); addLimitline(p, -dDirEcartMax); title("Distance"); xlabel("Temps (s)"); ylabel("Distance (mm)"); legend("Err. distance", "Err. retenue", "Err rotation"); % Rotation p = subplot(2, 3, 5); hold on; timeGraph(["oDirEcart", "oConsEcart", "oEcart"]); addLimitline(p, oDirEcartMax); addLimitline(p, oDirEcartMin); addLimitline(p, -oDirEcartMax); addLimitline(p, -oDirEcartMin); title("Rotation"); xlabel("Temps (s)"); ylabel("Angle (rad)"); legend("Err. direction", "Err. consigne", "Err. retenue"); % Securité p = subplot(2, 3, 6); hold on; timeGraph(["dDirEcart", "secFrontL", "secFrontR", "secBackL", "secBackR", "dErr"]); addLimitline(p, 0); addLimitline(p, margeSecurite); addLimitline(p, -margeSecurite); title("Distances de sécurité"); xlabel("Temps (s)"); ylabel("Distance (mm)"); legend("Err. distance", "Avant gauche", "Avant droite", "Arrière gauche", "Arrière droite", "Err. retenue"); % Fonctions function ts = getTS(name) global SIMULATION s; if SIMULATION == 1 ts = s.(name); else name = char(name); if s.isKey(name) ts = s(name); else fprintf("Données inconnues : %s\n", name); ts = timeseries(); end end end function pt = getTimePoints() global SIMULATION s; if SIMULATION == 1 pt = s.tout; else ts = getTS('time'); pt = ts.Time; end end function timeGraph(series) global SIMULATION_TIME p; m = inf; M = -inf; for sname=series serie = getTS(sname); plot(serie); if ~isempty(serie.Data) m = min(m, min(serie)); end if ~isempty(serie.Data) M = max(M, max(serie)); end end xlim([0 SIMULATION_TIME]); if (abs(m) ~= inf) && (abs(M) ~= inf) ylim([m M+1E-9]); end addTimeline(p); end function addLimitline(p, x) line(p.XLim, [x x], 'Color', [0.8 0.8 0.8], 'LineStyle', '--'); end function addTimeline(p) global t timelines; timeline = line([t t], p.YLim, 'Color', [0 0 0]); timelines = [timelines timeline]; end function play() global SIMULATION_TIME speed t playing; if playing == 1 return end startCpu=cputime; startT=t; n=0; playing=1; while t