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
|
/************************************************************************************************************************
* 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"
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};
int OriginalDispenserSpd_2PPS[MAX_SYSTEM_DISPENSERS] = {0};
bool DispenserPreSegmentReady[MAX_SYSTEM_DISPENSERS] = {false};
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
//
//********************************************************************************************************************
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);
#ifdef DEBUG_TEST_FUNCTIONS
// add control here
#else
#endif
}
//set 3 dancers to the profile positions
for (i = 0; i < MAX_SYSTEM_DISPENSERS; i++)
{
DispenserReady[i] = true;
}
return OK;
}
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 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; //not all configured heaters are ready
}
}
PreSegmentReady(Module_IDS,ModuleDone);
}
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;
TimerMotors_t HW_Motor_Id;
int segmentfirst_speed;
int CurrentSegment = 0;
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.
*/
for (Dispenser_i = 0;Dispenser_i <= MAX_SYSTEM_DISPENSERS;Dispenser_i++)
{
HW_Motor_Id = DispenserIdToMotorId[Dispenser_i];
Control3WayValvesWithCallback (Dispenser_i, 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[Dispenser_i] = 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;
TimerMotors_t HW_Motor_Id;
double segmentfirst_speed;
int CurrentSegment = 0;
for (Dispenser_i = 0;Dispenser_i <= MAX_SYSTEM_DISPENSERS;Dispenser_i++)
{
HW_Motor_Id = DispenserIdToMotorId[Dispenser_i];
//(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 (Dispenser_i, Dispenser_Mixer, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
MotorSetSpeed(HW_Motor_Id, segmentfirst_speed);
}
}
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;
}
|