diff --git a/servo_firmware/rx28/src/CTRL_sing_turn/CTRL_Dynamixel.c b/servo_firmware/rx28/src/CTRL_sing_turn/CTRL_Dynamixel.c
new file mode 100755
index 0000000000000000000000000000000000000000..17499e7775e3a25fb4f99d768b4cf4760c5430e9
--- /dev/null
+++ b/servo_firmware/rx28/src/CTRL_sing_turn/CTRL_Dynamixel.c
@@ -0,0 +1,230 @@
+#include <avr/interrupt.h>
+#include <avr/io.h>
+#include "MEM_Dynamixel.h"
+#include "CTRL_Dynamixel.h"
+#include "CFG_HW_Dynamixel.h"
+
+
+#define 	INT16_MAX   0x7fff
+#define 	INT16_MIN   (-INT16_MAX - 1)
+
+#define ADD_A_B(c,a,b) ({\
+int32_t x = (int32_t)a+b; \
+(x>32767)?(c = (int16_t)32767) : ((x<-32768)?(c = (int16_t)-32768):(c = (int16_t) x)); \
+})
+
+#define MULT_A_B(c,a,b) ({\
+int32_t x = (int32_t)a*b; \
+(x>32767)?(c = (int16_t)32767) : ((x<-32768)?(c = (int16_t)-32768):(c = (int16_t) x)); \
+})
+ 
+#define num_to_FFFFbit(c,a) ({\
+double x = (double)a; \
+(x>32767)?(c = (int16_t)32767) : ((x<-32768)?(c = (int16_t)-32768):(c = (int16_t) x)); \
+})
+
+
+void Ini_Position(void)
+{
+  int16_t Sensor_Value;      
+      // update position sensor value 
+  Sensor_Value=Read_Sensor(CTRL_Encoder_Port); 
+  Write_word_Dynamixel_RAM(Sensor_Value_L,Sensor_Value);
+  Write_word_Dynamixel_RAM(Present_Position_L,Sensor_Value);
+  Write_word_Dynamixel_RAM(Goal_Position_L,Sensor_Value);
+  Write_word_Dynamixel_RAM(Motor_Turns_L,0);
+  Write_byte_Dynamixel_RAM(Torque_Enable,1);
+}
+
+int16_t Read_Sensor(uint8_t port) {
+
+	int16_t ADCval;
+
+	ADMUX = port; // use #port ADC
+	ADMUX |= (1 << REFS0); // use AVcc as the reference
+	ADMUX &= ~(1 << ADLAR); // clear for 10 bit resolution
+
+	ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // 128 prescale for 8Mhz
+	ADCSRA |= (1 << ADEN); // Enable the ADC
+
+	ADCSRA |= (1 << ADSC); // Start the ADC conversion
+
+	while (ADCSRA & (1 << ADSC)); //   waits for the ADC to finish
+
+	ADCval = ADCL;
+	ADCval = (ADCH << 8) + ADCval; // ADCH is read so ADC can be updated again
+
+	return ADCval;
+}
+ 
+
+void Control_Cycle(void)
+{
+  
+    int16_t Motor_Turns,Sensor_Value,Present_Position,Goal_Position; 
+    //int16_t Motor_Accion,MotorDir,Error_Vector_0,Error_Vector_1,Error_Vector_2,Error_Vector_3;
+    int16_t Motor_Accion,MotorDir,Error_Vector_0,Error_Vector_1,Error_Vector_2;
+    //int16_t Integral_Value,Max_Integral_Value,Error_Margin,KP,KD,KI,Sensor_Resol, Max_Sensor_Range;
+    int16_t Error_Margin,KP,KD,Sensor_Resol, Max_Sensor_Range;
+    uint8_t Transition_Stage_Value;
+    int32_t  Motor_Accion_P=0;
+    int32_t  Motor_Accion_D=0;
+    //int32_t  Motor_Accion_I=0; 
+    
+      // update position sensor value
+    Sensor_Value = Read_Sensor(CTRL_Encoder_Port); 
+    Write_word_Dynamixel_RAM(Sensor_Value_L,Sensor_Value);
+        
+      // find direction of accion
+    Motor_Accion = Read_word_Dynamixel_RAM(Motor_Accion_L);
+    if (Motor_Accion<CTRL_ZERO){MotorDir=CTRL_Dir_CW;}
+    else{MotorDir=CTRL_Dir_CCW;}
+
+      // update motor turns
+    Transition_Stage_Value =  Read_byte_Dynamixel_RAM(Transition_Stage);
+    Motor_Turns=Read_word_Dynamixel_RAM(Motor_Turns_L);
+    
+    switch(Transition_Stage_Value) {
+     case 0:  //-3
+	if (Sensor_Value!=1023){
+	    if (MotorDir==CTRL_Dir_CW){ Transition_Stage_Value=3;  //0
+		Motor_Turns=Motor_Turns-1;
+	    }else { Transition_Stage_Value=1;}  //-2 
+	} 
+	break;   //...............................................
+     case 1:  //-2
+	if (Sensor_Value==0){ Transition_Stage_Value=2;  //-1
+	}else if (Sensor_Value==1023){ Transition_Stage_Value=0;}  //-3 
+	break;   //...............................................
+     case 2:  //-1
+	if (Sensor_Value!=0){
+	    if (MotorDir==CTRL_Dir_CW){ Transition_Stage_Value=1;  //-2
+	    }else { Transition_Stage_Value=3;}  //0 
+	}
+	break;   //...............................................
+     case 3:  //0
+	if (Sensor_Value==0) { Transition_Stage_Value=2;  //-1
+	}else if (Sensor_Value==1023) { Transition_Stage_Value=4;}  //1 
+	break;   //...............................................
+     case 4:  //1
+	if (Sensor_Value!=1023){
+	    if (MotorDir==CTRL_Dir_CCW){ Transition_Stage_Value=5;  //2
+	    }else { Transition_Stage_Value=3;}  //0 
+	}
+	break;   //...............................................
+     case 5:  //2
+	if (Sensor_Value==1023){ Transition_Stage_Value=4;  //1
+	}else if (Sensor_Value==0){ Transition_Stage_Value=6;}  //3 
+	break;   //...............................................
+     case 6:  //3
+	if (Sensor_Value!=0){
+	    if (MotorDir==CTRL_Dir_CCW){ Transition_Stage_Value=3;  //0
+		Motor_Turns=Motor_Turns+1;
+	    }else { Transition_Stage_Value=5;}  //2 
+	}
+	break;   //...............................................
+      default: 
+	;
+	break;   //...............................................
+    } 
+    Write_word_Dynamixel_RAM(Motor_Turns_L,Motor_Turns);
+    Write_byte_Dynamixel_RAM(Transition_Stage,Transition_Stage_Value);
+    
+     
+ 
+      // calc Position including  motor turns    
+    Sensor_Resol=Read_word_Dynamixel_RAM(Sensor_Resol_L);
+    Max_Sensor_Range=Read_word_Dynamixel_RAM(Max_Sensor_Range_L);
+    Present_Position = (int16_t) ((double)Motor_Turns*Sensor_Resol*360/ Max_Sensor_Range); // OJO max 26 vueltas   
+    ADD_A_B(Present_Position,Present_Position,Sensor_Value);    
+    Write_word_Dynamixel_RAM(Present_Position_L,Present_Position);
+
+      // Update Error Vector  3 
+    //Error_Vector_3=Read_word_Dynamixel_RAM(Error_Vector_2_L);
+    //Write_word_Dynamixel_RAM(Error_Vector_3_L,Error_Vector_3);
+      // Update Error Vector  2
+    Error_Vector_2=Read_word_Dynamixel_RAM(Error_Vector_1_L);
+    Write_word_Dynamixel_RAM(Error_Vector_2_L,Error_Vector_2);
+      // Update Error Vector  1
+    Error_Vector_1=Read_word_Dynamixel_RAM(Error_Vector_0_L);
+    Write_word_Dynamixel_RAM(Error_Vector_1_L,Error_Vector_1);
+      // Update Error Vector  0
+    Goal_Position=Read_word_Dynamixel_RAM(Goal_Position_L);
+    MULT_A_B(Present_Position,Present_Position,-1);
+    ADD_A_B(Error_Vector_0,Goal_Position,Present_Position);
+    Write_word_Dynamixel_RAM(Error_Vector_0_L,Error_Vector_0);
+
+      //   range where small errors are discarted
+    Error_Margin = Read_word_Dynamixel_RAM(Error_Margin_L);
+    if (Error_Vector_0<Error_Margin){
+      if (Error_Vector_0>(-1*Error_Margin)){ Write_word_Dynamixel_RAM(Motor_Accion_L,0);
+      return;    }
+    }
+      // CTRL_Law - algorithm http://lorien.ncl.ac.uk/ming/digicont/digimath/dpid1.htm
+    KP =	Read_word_Dynamixel_RAM(KP_L);
+    Motor_Accion_P = (int32_t)Error_Vector_0*KP/10;
+    KD =	Read_word_Dynamixel_RAM(KD_L);
+    Motor_Accion_D=  ((int32_t)Error_Vector_0-  Error_Vector_1*2 + Error_Vector_2 )*KD/100;
+    //KI =	Read_word_Dynamixel_RAM(KI_L);
+    //Integral_Value =	Read_word_Dynamixel_RAM(Integral_Value_L);
+    //ADD_A_B(Integral_Value,Integral_Value,Error_Vector_0);
+    //Motor_Accion_I=(int32_t)Integral_Value*KI/100;
+	// saturate Integral accion
+    //Max_Integral_Value =	Read_word_Dynamixel_RAM(Max_Integral_Value_L);
+    //if (Motor_Accion_I>Max_Integral_Value){Motor_Accion_I=Max_Integral_Value;}
+    //else if (Motor_Accion_I<(-Max_Integral_Value)){Motor_Accion_I=-Max_Integral_Value;}
+
+    //ADD_A_B(Motor_Accion,Motor_Accion_I,Motor_Accion_D);
+    //ADD_A_B(Motor_Accion,Motor_Accion,Motor_Accion_P);
+    ADD_A_B(Motor_Accion,Motor_Accion_D,Motor_Accion_P);
+
+    //Write_word_Dynamixel_RAM(Integral_Value_L,Integral_Value);
+    Write_word_Dynamixel_RAM(Motor_Accion_L,Motor_Accion);
+}
+
+void HW_Security(void)
+{
+   ; // TODO revisar corriente y temperatura 
+}
+
+void Write_Actuator(void)
+{
+  uint16_t PWM_Value;
+  int16_t MotorDir,Motor_Accion,Dead_Zone,Max_PWM_Value,Temp;
+  
+    Motor_Accion = Read_word_Dynamixel_RAM(Motor_Accion_L);
+      // find direction of accion
+    if (Motor_Accion<CTRL_ZERO){MotorDir=CTRL_Dir_CW;}
+    else{MotorDir=CTRL_Dir_CCW;}
+    
+      // add motor deadzone to Motor accion if not zero
+     // and if needed Saturate accion to max PWM_Value
+   Dead_Zone=Read_word_Dynamixel_RAM(Dead_Zone_L);
+   Max_PWM_Value= Read_word_Dynamixel_RAM(Max_PWM_Value_L);
+   if (Motor_Accion==CTRL_ZERO)
+	{PWM_Value=CTRL_ZERO;}
+   else{  
+        MULT_A_B(Temp,Motor_Accion,MotorDir);
+	ADD_A_B(Temp,Temp,Dead_Zone);
+        if ( Temp > Max_PWM_Value)
+	    { PWM_Value =  Max_PWM_Value;}        // Saturate accion to max PWM_Value
+	else
+	    { PWM_Value = (uint16_t)Temp;}// add motor deadzone to Motor accion
+    }  
+     
+    
+    // place PWM value on respective pin
+	if (PWM_Value > CTRL_ZERO) {
+		if (MotorDir == CTRL_Dir_CCW) {
+			SET_CW_PWM_MOTOR(CTRL_ZERO); //PB1 => set PWM for X% duty cycle
+			SET_CCW_PWM_MOTOR(PWM_Value); //PB2 => set PWM for Y% duty cycle
+		} else {
+			SET_CCW_PWM_MOTOR(CTRL_ZERO); //PB2 => set PWM for Y% duty cycle
+			SET_CW_PWM_MOTOR(PWM_Value); //PB1 => set PWM for X% duty cycle
+		}
+	} else {
+		SET_CW_PWM_MOTOR(CTRL_ZERO); //PB1 => set PWM for X% duty cycle
+		SET_CCW_PWM_MOTOR(CTRL_ZERO); //PB2 => set PWM for Y% duty cycle
+	}
+}
+