/************************************************************************************************************************ * Thread_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 "thread.h" #include "thread_ex.h" #include "../control/control.h" #include "../control/pidalgo.h" #include "PMR/Hardware/HardwareMotor.pb-c.h" #include "PMR/Hardware/HardwareMotorType.pb-c.h" #include "PMR/Hardware/HardwareDancerType.pb-c.h" #include "PMR/Printing/JobSegment.pb-c.h" #include "PMR/Printing/JobTicket.pb-c.h" #include "StateMachines/Printing/PrintingSTM.h" #include "drivers/Motors/Motor.h" #include "drivers/Danser_SSI/ssi_comm.h" #include "drivers/Heater/TemperatureSensor.h" #include "drivers/Heater/Heater.h" ////////////////////////////////State machine operation//////////////////////////////////// //the state machine operation is used to operate in runtime correct profile flow execution //by recieved esign flow of the user from the UI /////////////////////////////////////////////////////////////////////////////////////////// uint32_t CurrentControlledSpeed[MAX_THREAD_MOTORS_NUM] = {0}; TimerMotors_t ThreadMotorIdToMotorId[MAX_THREAD_MOTORS_NUM] = {HARDWARE_MOTOR_TYPE__MOTO_RDRIVING,HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING,HARDWARE_MOTOR_TYPE__MOTO_LDRIVING,HARDWARE_MOTOR_TYPE__MOTO_WINDER,HARDWARE_MOTOR_TYPE__MOTO_SCREW}; HardwareDancerType ThreadMotorIdToDancerId[MAX_THREAD_MOTORS_NUM] = {FEEDER_DANCER,NUM_OF_DANCERS,POOLER_DANCER,WINDER_DANCER,NUM_OF_DANCERS}; uint32_t ControlIdtoMotorId [MAX_THREAD_MOTORS_NUM] = {0xFF}; int OriginalMotorSpd_2PPS[MAX_THREAD_MOTORS_NUM] = {0}; typedef struct { bool m_isEnabled; int32_t m_SetParam; float m_mesuredParam; float m_preError; float m_integral; float m_calculatedError; bool m_isReady; PID_Config_Params m_params; }MotorControlConfig_t; MotorControlConfig_t MotorControlConfig[MAX_THREAD_MOTORS_NUM]; uint32_t DeviceId2Motor[MAX_THREAD_MOTORS_NUM]; uint32_t PreviousPosition = 0, CurrentPosition = 0; double totalLength = 0.0; double CurrentRequestedLength = 0.0; double CurrentProcessedLength = 0.0; typedef void (* ProcessedLengthFunc)(void); ProcessedLengthFunc ProcessedLengthFuncPtr = NULL; // segment/intersegment/distance to spool finished void ThreadSegmentEnded(void); void ThreadInterSegmentEnded(void); void ThreadDistanceToSpoolEnded(void); ////////////////////////Slow Motor State//////////////////////////////////// //uint32_t ThreadPreSegmentState(void *JobDetails); //////////////////////////////////////////////////////////////////////////// /******************************************************************** * * Name : GTIME_Delta_Time_Pass * * Parameters : start_time. * * Return : time pass from start time * * Description : * *********************************************************************/ uint32_t Control_Delta_Position_Pass(uint32_t Current_Read,uint32_t Previous_Read) { uint32_t Time_Pass; #define MAX_COUNTER 0x3FFF //14 bits if (Current_Read < Previous_Read) Time_Pass = (MAX_COUNTER - Previous_Read) + Current_Read + 1; else Time_Pass = Current_Read - Previous_Read; return (Time_Pass); } /***************************************************************************************** * * * * * * * **************************************************************************************/ uint32_t ThreadSpeedControlCBFunction(uint32_t IfIndex, uint32_t ReadValue) { //read value is the dancer angle int index=MAX_THREAD_MOTORS_NUM; if (IfIndex>>8 != IfTypeThread) { LOG_ERROR (IfIndex, "Wrong Interface type"); return 0xFFFFFFFF; } index = IfIndex&0xFF; /* for (i=0;i= MotorControlConfig[index].m_params.MAX) { MotorControlConfig[index].m_calculatedError = MotorControlConfig[index].m_params.MAX; } if (MotorControlConfig[index].m_calculatedError < MotorControlConfig[index].m_params.MIN) { MotorControlConfig[index].m_calculatedError = MotorControlConfig[index].m_params.MIN; } //SetMotorFreq (index, MotorControlConfig[index].m_calculatedError); } return OK; } void ThreadUpdateProcessLength (double length, void *Funcptr) { CurrentRequestedLength = length; CurrentProcessedLength = 0; ProcessedLengthFuncPtr = (ProcessedLengthFunc)Funcptr; } uint32_t ThreadLengthCBFunction(uint32_t IfIndex, uint32_t ReadValue) { uint32_t positionDiff = 0; double length = 0.0; int index = MAX_THREAD_MOTORS_NUM; if (IfIndex>>8 != IfTypeThread) { LOG_ERROR (IfIndex, "Wrong Interface type"); return 0xFFFFFFFF; } index = IfIndex&0xFF; if (index != FEEDER_MOTOR) { LOG_ERROR (IfIndex, "Wrong Motor"); return 0xFFFFFFFF; } CurrentPosition = MotorGetPositionFromFPGA_Res(ThreadMotorIdToMotorId[index]); positionDiff = Control_Delta_Position_Pass(CurrentPosition,PreviousPosition); PreviousPosition = CurrentPosition; // total length = (position diff / full cycle) * pulley perimeter //(positionDiff/pulseperround)*((2*PI*motor_Radius) length = (positionDiff/MotorsCfg[ThreadMotorIdToMotorId[index]].pulseperround)*(2*PI*MotorsCfg[ThreadMotorIdToMotorId[index]].pulleyradius); totalLength+=length; CurrentProcessedLength+=length; if (CurrentProcessedLength>=CurrentRequestedLength ) { // segment/intersegment/distance to spool finished if (ProcessedLengthFuncPtr) ProcessedLengthFuncPtr(); } return OK; } uint32_t ThreadControlCBFunction(uint32_t IfIndex, uint32_t ReadValue) { //#define MAX_CONTROL_SAMPLES 6 //extern uint32_t MotorSamples[MAX_THREAD_MOTORS_NUM][MAX_CONTROL_SAMPLES]; //extern int MotorSamplePointer[MAX_THREAD_MOTORS_NUM]; //read value is the dancer angle int i,index=MAX_THREAD_MOTORS_NUM; int DancerId; int32_t TranslatedReadValue, avreageSampleValue = 0; double NormalizedError; if (IfIndex>>8 != IfTypeThread) { LOG_ERROR (IfIndex, "Wrong Interface type"); return 0xFFFFFFFF; } index = IfIndex&0xFF; /*for (i=0;i= MotorsControl[index].pvinputfilterfactormode) MotorSamplePointer[index] = 0; for (i=0;i= MotorControlConfig[index].m_params.MAX) { MotorControlConfig[index].m_calculatedError = MotorControlConfig[index].m_params.MAX; } if (MotorControlConfig[index].m_calculatedError < MotorControlConfig[index].m_params.MIN) { MotorControlConfig[index].m_calculatedError = MotorControlConfig[index].m_params.MIN; }*/ uint32_t calculated_speed = (1-MotorControlConfig[index].m_calculatedError)*OriginalMotorSpd_2PPS[index]; if (abs(calculated_speed-CurrentControlledSpeed[index])>5) { CurrentControlledSpeed[index] = calculated_speed; MotorSetSpeed(ThreadMotorIdToMotorId[index], calculated_speed, MotorsCfg[ThreadMotorIdToMotorId[index]].microstep); } } return OK; } //******************************************************************************************************************** //******************************************************************************************************************** /*#ifdef DEBUG_TEST_FUNCTIONS uint32_t Debug_Get_Dancer_Read(uint32_t DancerId, uint32_t Parameter1, uint32_t Parameter2) { return (rand() % (103 + 1 + 103) - 103); } #endif*/ uint32_t ThreadInitialTestStub(HardwareMotor * request) { //MotorsConfigMessage(request); ThreadPrepareState(request); ThreadPreSegmentState(request); return OK; } bool InitialProcess = false; //******************************************************************************************************************** uint32_t ThreadPrepareState(void *JobDetails) { int Motor_i, HW_Motor_Id, Pid_Id; //start thread control for all motors for (Motor_i = 0;Motor_i < MAX_THREAD_MOTORS_NUM;Motor_i++) { HW_Motor_Id = ThreadMotorIdToMotorId[Motor_i]; Pid_Id = Motor_i;/*ThreadMotorIdToControlId[Motor_i];*/ MotorControlConfig[Motor_i].m_params.MAX = 1; MotorControlConfig[Motor_i].m_params.MIN = MotorsControl[Pid_Id].outputproportionalpowerlimit*-1; MotorControlConfig[Motor_i].m_params.Kd = MotorsControl[Pid_Id].derivativetime; MotorControlConfig[Motor_i].m_params.Kp = MotorsControl[Pid_Id].proportionalgain; MotorControlConfig[Motor_i].m_params.Ki = MotorsControl[Pid_Id].integraltime; MotorControlConfig[Motor_i].m_params.epsilon = 0.01; MotorControlConfig[Motor_i].m_params.dt = 50; MotorControlConfig[Motor_i].m_calculatedError = 0; MotorControlConfig[Motor_i].m_integral = 0; MotorControlConfig[Motor_i].m_isEnabled = true; MotorControlConfig[Motor_i].m_isReady = true; MotorControlConfig[Motor_i].m_mesuredParam = 0; MotorControlConfig[Motor_i].m_preError = 0; MotorControlConfig[Motor_i].m_SetParam = 0;//need to update SetParams on presegment stage MotorSetDirection((TimerMotors_t)HW_Motor_Id,MotorsCfg[HW_Motor_Id].directionthreadwize); #ifdef DEBUG_TEST_FUNCTIONS if (Motor_i == FEEDER_MOTOR) // dryer motor is speed controlled. later a speed sensor will be utilized, but for now it will not be controlled ControlIdtoMotorId[Motor_i] = AddControlCallback(ThreadLengthCBFunction, eHundredMillisecond,MotorGetPositionFromFPGA,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToDancerId[Motor_i],Motor_i); if (Motor_i == FEEDER_MOTOR) // dryer motor is speed controlled. later a speed sensor will be utilized, but for now it will not be controlled ControlIdtoMotorId[Motor_i] = AddControlCallback(ThreadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToDancerId[Motor_i],Motor_i); if (Motor_i == POOLER_MOTOR) // dryer motor is speed controlled. later a speed sensor will be utilized, but for now it will not be controlled ControlIdtoMotorId[Motor_i] = AddControlCallback(ThreadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToDancerId[Motor_i],Motor_i); /*if (HW_Motor_Id == HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING) // dryer motor is speed controlled. later a speed sensor will be utilized, but for now it will not be controlled //AddControlCallback(ThreadSpeedControlCBFunction, eOneMillisecond,MotorGetSpeed,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToMotorId[Motor_i],0); // continue; AddControlCallback(ThreadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,ThreadMotorIdToDancerId[Motor_i],Motor_i); else if ((HW_Motor_Id == HARDWARE_MOTOR_TYPE__MOTO_WINDER)||(HW_Motor_Id == HARDWARE_MOTOR_TYPE__MOTO_LDRIVING)||(HW_Motor_Id == HARDWARE_MOTOR_TYPE__MOTO_RDRIVING)) AddControlCallback(ThreadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToDancerId[Motor_i],Motor_i);*/ #else if (Motor_i == HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING) // dryer motor is speed controlled. later a speed sensor will be utilized, but for now it will not be controlled continue; //AddControlCallback(ThreadSpeedControlCBFunction, eOneMillisecond,MotorGetSpeed,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToMotorId[Motor_i],Motor_i); else if ((Motor_i == HARDWARE_MOTOR_TYPE__MOTO_WINDER)||(Motor_i == HARDWARE_MOTOR_TYPE__MOTO_LDRIVING)||(Motor_i == HARDWARE_MOTOR_TYPE__MOTO_RDRIVING)) AddControlCallback(ThreadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+Motor_i),ThreadMotorIdToDancerId[Motor_i],Motor_i); #endif } Winder_Prepare(); //set 3 dancers to the profile positions InitialProcess = true; return OK; } //******************************************************************************************************************** uint32_t ThreadPreSegmentState(void *JobDetails) { //set the speed only before the first segment, speed is constant accros job JobTicket* JobTicket = JobDetails; int Motor_i, HW_Motor_Id; int process_speed = JobTicket->processparameters->dyeingspeed; process_speed = 50; //debug for (Motor_i = 0;Motor_i <= WINDER_MOTOR;Motor_i++) { HW_Motor_Id = ThreadMotorIdToMotorId[Motor_i]; //(Speed*uStep*PPR)/((2*PI*motor_Radius) double motor_speed = (process_speed * MotorsCfg[HW_Motor_Id].pulseperround * MotorsCfg[HW_Motor_Id].microstep)/(2*PI* MotorsCfg[HW_Motor_Id].pulleyradius); //MotorControlConfig[Motor_i].m_SetParam = motor_speed; OriginalMotorSpd_2PPS[Motor_i] = (int)motor_speed; } //ControlStart(); // set the new speed in the dryer motor to the speed of the new segment MotorSetSpeed(HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING, OriginalMotorSpd_2PPS[DRYER_MOTOR], MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING].microstep); //only for testing - when control works, these motors will take their speed from the dryer MotorSetSpeed(HARDWARE_MOTOR_TYPE__MOTO_LDRIVING, OriginalMotorSpd_2PPS[POOLER_MOTOR], MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_LDRIVING].microstep); //only for testing - when control works, these motors will take their speed from the dryer MotorSetSpeed(HARDWARE_MOTOR_TYPE__MOTO_RDRIVING, OriginalMotorSpd_2PPS[FEEDER_MOTOR], MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RDRIVING].microstep); MotorSetSpeed(HARDWARE_MOTOR_TYPE__MOTO_RLOADING, 1, 1); MotorSetSpeed(HARDWARE_MOTOR_TYPE__MOTO_LLOADING, 1,1); // activate control fr all motors //set speed for both rocker motors //wait for all motors to get to the required speed (set the target speed for the control to check) //call the job state machine when the thread system is ready if ((InitialProcess==false) && JobTicket->enableintersegment == true) { ThreadUpdateProcessLength (JobTicket->intersegmentlength,(void *)ThreadInterSegmentEnded); } else { PreSegmentReady(Module_Thread,ModuleDone); InitialProcess = false; } return OK; } void ThreadInterSegmentEnded(void) { PreSegmentReady(Module_Thread,ModuleDone); } void ThreadSegmentEnded(void) { SegmentReady(Module_Thread,ModuleDone); } void ThreadDistanceToSpoolEnded(void) { } //******************************************************************************************************************** uint32_t ThreadSegmentState(void *JobDetails, int SegmentId) { JobTicket* JobTicket = JobDetails; ThreadUpdateProcessLength (JobTicket->segments[SegmentId]->length,(void *)ThreadSegmentEnded); return OK; } //******************************************************************************************************************** uint32_t ThreadEndState(void *JobDetails) { int Motor_i; for ( Motor_i = 0;Motor_i < MAX_THREAD_MOTORS_NUM;Motor_i++) { StopMotor(ThreadMotorIdToMotorId[Motor_i],Hard_Hiz); } StopMotor(HARDWARE_MOTOR_TYPE__MOTO_RLOADING,Hard_Hiz); StopMotor(HARDWARE_MOTOR_TYPE__MOTO_LLOADING,Hard_Hiz); return OK; } //******************************************************************************************************************** void ThreadStartPrinting(void) { //PrintingIterate(); } //******************************************************************************************************************** //******************************************************************************************************************** void ThreadStopPrinting(void) { //PrintingIterate(); }