aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Embedded_SW/Embedded/Modules/IDS/IDS_print.c
blob: 092fbb252ffbd8a07c37413f3778b1e98c20cdee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/************************************************************************************************************************
 * Ids_print.c
 * Printing module is responsible for :
     * operating diffrent winding algorithms with predefined parameters from the UI
     * operating the dispensers according to predefined dispensing rate from the UI
 **************************************************************************************************************************/
#include "include.h"
#include "ids.h"
#include "ids_ex.h"
#include "../control/control.h"
#include "../control/pidalgo.h"
#include "../thread/thread.h"
#include "PMR/Hardware/Hardwaremotor.pb-c.h"
#include "PMR/Hardware/HardwareDispenser.pb-c.h"
#include "StateMachines/Printing/printingSTM.h"
#include "drivers/motors/motor.h"
#include "drivers/valves/valve.h"

#include "modules/heaters/heaters.h"


typedef struct
{
    bool                m_isEnabled;
    float            m_SetParam;
    float            m_mesuredParam;
    float               m_preError;
    float               m_integral;
    float               m_calculatedError;
    bool                m_isReady;
    PID_Config_Params   m_params;
}DispenserControlConfig_t;
HardwarePidControl DispensersControl[MAX_SYSTEM_DISPENSERS] = {0};

int32_t DispenserSamples[MAX_SYSTEM_DISPENSERS][MAX_CONTROL_SAMPLES] = {0};
int DispenserSamplePointer[MAX_SYSTEM_DISPENSERS] = {0};
double DispenserNormalizedErrorCoEfficient[MAX_SYSTEM_DISPENSERS] = {0};

HardwarePidControlType ThreadDispenserIdToControlId[MAX_SYSTEM_DISPENSERS] = {  HARDWARE_PID_CONTROL_TYPE__Dispenser1,HARDWARE_PID_CONTROL_TYPE__Dispenser2,HARDWARE_PID_CONTROL_TYPE__Dispenser3,HARDWARE_PID_CONTROL_TYPE__Dispenser4,HARDWARE_PID_CONTROL_TYPE__Dispenser5,HARDWARE_PID_CONTROL_TYPE__Dispenser6,HARDWARE_PID_CONTROL_TYPE__Dispenser7,HARDWARE_PID_CONTROL_TYPE__Dispenser8};

bool    DispenserReady[MAX_SYSTEM_DISPENSERS] = {true};

/******************** STRUCTURES AND ENUMs  ********************************************/
/******************** GLOBAL PARAMETERS  ********************************************/
DispenserControlConfig_t DispenserControlConfig[MAX_SYSTEM_DISPENSERS];
uint32_t    ControlIdtoDispenserId [MAX_SYSTEM_DISPENSERS] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
int OriginalDispenserSpd_2PPS[MAX_SYSTEM_DISPENSERS] = {0,0,0,0,0,0,0,0};
bool         DispenserPreSegmentReady[MAX_SYSTEM_DISPENSERS] = {true,true,true,true,true,true,true,true};
int JobBrushStopId = 0;

uint32_t IDS_DispenserPidRequestMessage(HardwarePidControl* request)
{
    int Dispenser_i,i;
    //int temp;
    for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
    {
        if (ThreadDispenserIdToControlId[i] == request->hardwarepidcontroltype)
        {
            Dispenser_i = i;
            break;
        }
    }
    memcpy (&DispensersControl[Dispenser_i],request,sizeof(HardwarePidControl));
    if (DispensersControl[Dispenser_i].pvinputfilterfactormode > MAX_CONTROL_SAMPLES)
        DispensersControl[Dispenser_i].pvinputfilterfactormode = MAX_CONTROL_SAMPLES;
    for (i = 0;i < DispensersControl[Dispenser_i].pvinputfilterfactormode; i++)
        DispenserSamples[Dispenser_i][i] = 0;  //reset the samples value for control beginning
    /*DispenserNormalizedErrorCoEfficient[Dispenser_i] = (2*PI*DancersCfg[ThreadDispenserIdToDancerId[Dispenser_i]].armlength);
    temp = 1<<(DancersCfg[ThreadDispenserIdToDancerId[Dispenser_i]].resolutionbits);
    temp=(100*(temp-1)*DancersCfg[ThreadDispenserIdToDancerId[Dispenser_i]].maximalmovementmm);
    DispenserNormalizedErrorCoEfficient[Dispenser_i] = DispenserNormalizedErrorCoEfficient[Dispenser_i] / temp;*/

    return OK;
}

/*
 * IDS Printing support
 * Prepare: build pressure in all participating dispensers
 * Print - dispense ink to the printing head
 * stop - stop dispensing
 *
 * control processes:
 * on prepare stage - each 10msec against the pressure sensors
 * on print stage - every 10/100 msec against the speed sensor
 *
 * */
//Dispenser Pressure control
//callback - calls printing stm with the result

// registration - 10 msec, dispenser pressure sensor
//    AddControlCallback(DeviceId2Dispenser[DispenserId], DispenserControlCBFunction, eHundredMillisecond);
// start the dispenser pressure building - move up in a TBD speed, valve closed
//Dispenser Speed control
//callback - handles speed
// registration - 10msec, dispenser speed senseo
// start the dispensing - move up according to the segment defined speed and microstepping, valve opened
//
void DispenserPrepareReady(void)
{
    int i;
    for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
    {
        if (DispenserReady[i] == false)
        {
            return; //not all configured Dispensers are ready
        }
    }
    PrepareReady(Module_IDS,ModuleDone);
}

//********************************************************************************************************************
 uint32_t IDSPrepareState(void *JobDetails)
{
    int Motor_i, HW_Motor_Id, Pid_Id,i;
    //start IDS control for all motors
    for (Motor_i = 0;Motor_i < MAX_SYSTEM_DISPENSERS;Motor_i++)
    {
        HW_Motor_Id = DispenserIdToMotorId[Motor_i];
        Pid_Id = Motor_i;/*IDSMotorIdToControlId[Motor_i];*/
            DispenserControlConfig[Motor_i].m_params.MAX = 1;
            DispenserControlConfig[Motor_i].m_params.MIN = DispensersControl[Pid_Id].outputproportionalpowerlimit*-1;
            DispenserControlConfig[Motor_i].m_params.Kd = DispensersControl[Pid_Id].derivativetime;
            DispenserControlConfig[Motor_i].m_params.Kp = DispensersControl[Pid_Id].proportionalgain;
            DispenserControlConfig[Motor_i].m_params.Ki = DispensersControl[Pid_Id].integraltime;
            DispenserControlConfig[Motor_i].m_params.epsilon = 0.01;
            DispenserControlConfig[Motor_i].m_params.dt = eHundredMillisecond;
            DispenserControlConfig[Motor_i].m_calculatedError = 0;
            DispenserControlConfig[Motor_i].m_integral = 0;
            DispenserControlConfig[Motor_i].m_isEnabled = true;
            DispenserControlConfig[Motor_i].m_isReady = true;
            DispenserControlConfig[Motor_i].m_mesuredParam = 0;
            DispenserControlConfig[Motor_i].m_preError = 0;
            DispenserControlConfig[Motor_i].m_SetParam = 0;//need to update SetParams on presegment stage

            MotorSetDirection((TimerMotors_t)HW_Motor_Id,MotorsCfg[HW_Motor_Id].directionthreadwize); //set the dispenser to the
#warning activate valve
            /*Start the dispensers to build initial pressure
             * check different handling for dispensers that participate in the first segment and idle dispensers
             * start control for initial pressure
             *
             */
            //ValveCommand (Enable,MixerDirection);
    }
    //set 3 dancers to the profile positions
    for (i = 0; i < MAX_SYSTEM_DISPENSERS; i++)
    {
        DispenserReady[i] = true;
    }
    DispenserPrepareReady();
    return OK;
}

//********************************************************************************************************************

 uint32_t IDS_Valve_PresegmentReady(uint32_t deviceID, uint32_t ReadValue)
 {
     int i;
     DispenserPreSegmentReady[deviceID] = true;
     for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
     {
         if (DispenserPreSegmentReady[i] == false)
         {
             return OK; //not all configured heaters are ready
         }
     }
     PreSegmentReady(Module_IDS,ModuleDone);
  return OK; // all configured heaters are ready
 }
uint32_t IDSPreSegmentState(void *JobDetails, int SegmentId)
{
//set the speed only before the first segment, speed is constant accros job
    JobTicket* JobTicket = JobDetails;
    int Dispenser_i,n_dispensers,DispenserId;
    TimerMotors_t HW_Motor_Id;

    JobBrushStopId = 0;

    // activate control fr all motors
    /* wait for all dispensers  to get to the required pressure
     * move the presegment ready when all dispensers are ready.
     */
    if (SegmentId>=JobTicket->n_segments)
        {
            LOG_ERROR(SegmentId,"Error Segment");
            return ERROR;
        }
    if (JobBrushStopId>=JobTicket->segments[SegmentId]->n_brushstops)
    {
        LOG_ERROR(JobBrushStopId,"Error JobBrushStopId");
        return ERROR;
    }
    if (JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->n_dispensers)
    {
        n_dispensers = JobBrushStopId>=JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->n_dispensers;
        for (Dispenser_i = 0;Dispenser_i <= n_dispensers;Dispenser_i++)
        {
            DispenserId = JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->index;
            HW_Motor_Id = DispenserIdToMotorId[DispenserId];
            if (MotorsCfg[HW_Motor_Id].hardwaremotortype != DispenserIdToMotorId[DispenserId])//unconfigured dispenser
                continue;
            Control3WayValvesWithCallback ((Valves_t)DispenserId, MidTank_Dispenser, IDS_Valve_PresegmentReady); //direction: MidTank_Dispenser or Dispenser_Mixer

            MotorStop(HW_Motor_Id,Hard_Stop);
            if (JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->has_dispenserstepdivision)
                MotorSetMicroStep(HW_Motor_Id,JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->dispenserstepdivision);
            else
                MotorSetMicroStep(HW_Motor_Id,MotorsCfg[HW_Motor_Id].microstep);
            DispenserPreSegmentReady[DispenserId] = false;

        }
    }
    //call the job state machine when the thread system is ready
    //PreSegmentReady(Module_IDS,ModuleDone);

    return OK;
}

//********************************************************************************************************************
 uint32_t IDSSegmentState(void *JobDetails, int SegmentId)
{
     JobTicket* JobTicket = JobDetails;
     int Dispenser_i,n_dispensers,DispenserId;
     TimerMotors_t HW_Motor_Id;
     double segmentfirst_speed;
     int CurrentSegment = SegmentId;


     if (CurrentSegment>=JobTicket->n_segments)
         {
             LOG_ERROR(CurrentSegment,"Error Segment");
             return ERROR;
         }
     if (JobBrushStopId>=JobTicket->segments[CurrentSegment]->n_brushstops)
     {
         LOG_ERROR(JobBrushStopId,"Error JobBrushStopId");
         return ERROR;
     }
     if (JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->n_dispensers)
     {
         n_dispensers = JobBrushStopId>=JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->n_dispensers;
         for (Dispenser_i = 0;Dispenser_i <= n_dispensers;Dispenser_i++)
         {
             DispenserId = JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->index;
             HW_Motor_Id = DispenserIdToMotorId[DispenserId];
             if (MotorsCfg[HW_Motor_Id].hardwaremotortype != DispenserIdToMotorId[DispenserId])//unconfigured dispenser
                 continue;
             //(Speed*uStep*PPR)/((2*PI*Dispenser_Radius)
             segmentfirst_speed = JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->nanolitterpersecond/
                     JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->nanoliterperpulse;
    //         double Dispenser_speed = (segmentfirst_speed *  MotorsCfg[HW_Motor_Id].pulseperround)/(2*PI* MotorsCfg[HW_Motor_Id].pulleyradius);
             //DispenserControlConfig[Dispenser_i].m_SetParam = Dispenser_speed;
    //         OriginalDispenserSpd_2PPS[Dispenser_i] = (int)Dispenser_speed;
             if ((int)segmentfirst_speed > 0)
                 {
                     Control3WayValvesWithCallback (DispenserId, Dispenser_Mixer, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
                     MotorSetSpeed(HW_Motor_Id, segmentfirst_speed);
                     HeatingTestSendResonse(0,false,0, Dispenser_Mixer,DispenserId, segmentfirst_speed,SegmentId,JobBrushStopId,"Dispenser !!!!!!!!!!!");
                 }
         }
     }

    return OK;
}

//********************************************************************************************************************
 uint32_t IDSEndState(void *JobDetails)
{
     int Dispenser_i;
     for ( Dispenser_i = 0;Dispenser_i < MAX_SYSTEM_DISPENSERS;Dispenser_i++)
     {
        MotorStop(DispenserIdToMotorId[Dispenser_i],Hard_Hiz);
        Control3WayValvesWithCallback (Dispenser_i, MidTank_Dispenser, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
     }

    return OK;
}