Ward-Leonard control system: Theory and demonstration

When choosing the main motor for large scale electromechanical systems, two are the main candidate solutions: The AC induction motor and the DC induction motor. In most cases, the AC motor is selected, because of its simplicity, lower price and higher reliability. However, there are cases where the DC machine is preferred and those are where the precision of the speed control is crucial. Since the speed and torque outputs of the DC motor are linear, the control algorithm is a lot simpler. The main objectives of power electronics drives for induction motors are to provide similar control capacity compared to DC motors.

The Ward-Leonard control system is the best solution to have a very smooth speed control for the full range of the DC motor. Nowadays similar results can be achieved using power electronics converters and those drives have gradually replaced older Ward-Leonard systems. Typically, to control the speed of a DC motor either the voltage of the armature or the current of the field coil. While the control of the field coil current has higher efficiency (when not using power electronics) the speed range is limited, as the armature current cannot exceed the nominal value. On the other hand, as the armature current value is a lot higher than the field coil current, the regulation of this current with resistive devices will lead to major power loss. The armature voltage regulation can be provided through a voltage divider or using a resistor connected in series. Due to the advances in the area of power electronics, nowadays it can also be provided using a thyristor 2 or 6 pulse bridge or using an AC/DC power supply.

The Ward-Leonard control system provides a DC voltage to the armature that can be adjusted. This voltage is provided by a DC generator. As a result, it can vary from zero to the nominal value of the DC motor, providing a wide range of speed control. The output voltage of a DC generator is mainly a function of the rotor speed as well as its field coil current. So, in the Ward-Leonard system, the speed is kept almost constant and the field current is adjusted using a voltage divider. By adjusting the field current of the DC generator, the armature voltage of the DC motor is adjusted, controlling in the end the rotor speed. Finally, a motor is needed to rotate the DC generator. The type of the motor is irrelevant so it can be a DC motor, an AC induction motor or even an internal combustion or steam engine. The use of such a system with an internal combustion engine was described in Ward Leonard's patent application in 1903. Typical applications of the Ward-Leonard control systems are elevators and radars where the speed as well as position need to be precise. With the advances of SCRs in the 1980s, thyristor bridges started to replace those systems. The thyristor bridges, while being a lot more power efficient, small and cost-effective have extremely low power factor. Those bridges are being replaced with PFC converters with IGBTs or drives with induction motors.

The following figure shows the control system schematic. The main DC motor is machine 3. The field coil is powered by a DC current supply (diode 6 pulse bridge) and the current is at its nominal value. Machine 2, which is the DC generator supplies the voltage to the DC motor armature. The field current varies from zero to its nominal value and is controlled by a DC power supply, or simply by a voltage divider from the DC source. Machine 1 is an induction motor which rotates the DC generator. The rotor speed is almost constant (there is a small variation depending on the load, however this can be counterbalanced by adjusting the voltage divider for the field current.

A common issue of the induction machine is the very high value of the inrush current. That is why a soft starter is usually applied, either using a star-delta topology or more frequently using a power electronics converter. In the following video, the operation of the star-delta topology is shown.

Finally, a laboratory Ward Leonard Control system is shown in the following video. The main DC motor is the front left (which makes the front right machine the load).

Comparison of 4 USB power supplies

Having recently installed a Raspberry Pi 2 server running 24/7, which is powered through a 5V micro USB port (recommended power supply nominal current: 1.8A), I wanted to test different USB supplies in order to see which is the most efficient to use.

The models I tested were:

  1. Apple A1400 charger from an iPhone 4. Max. Current: 1A.
  2. LG MCS-04 charger from an LG phone. Max. Current: 1.8A.
  3. LG MCS-02 charger from an LG phone. Max. Current: 0.85A.
  4. Garmin PSAI05R-050Q charger from an Edge 510. Max. Current: 0.5A.

The tests were done powering a constant current load through a 1.5m USB cable, with a total resistance of 1Ω. The power losses of the cable were neglected as the aim was to measure the absolute efficiency of the wall chargers. The chargers were powered by 230V/50Hz and Zes Zimmer precision power analyzer was used to measure the efficiency and the power factor of each charger.

The results of the test are shown in the following figures.

First the results of the power efficiency are shown. The Garmin Charger has the lowest power rating and also the lowest efficiency. The LG MCS-04 which has the highest power rating, has also the highest efficiency. However, the Apple charger has a lower power efficiency than the LG MCS-02 charger, which has a lower rating. On the other hand, the Apple charger has the lowest standby power consumption (the power analyzer couldn't measure it) whereas it could measure some mW on all the other chargers.

Next, the power factor measurements are shown in the following figure.

The power factor measurements are similar for all chargers and all very low. Yes, the chargers' input power is only some W, but there are millions plugged in at the same time. The power factor is expected to be this low due to the diode full bridge rectification of the ac voltage, followed by a capacitor, expected to have a high capacitance value, in order to help the output voltage stabilization (together with the DC/DC converter controller). Cheap counterfeits use a single-diode (half) rectification, so their power factor should be even lower.

All in all, although the power efficiency of the provided charger is not the main criterium when selecting a mobile phone, due to the large number of chargers, the suppliers were forced to improve the power efficiency of their chargers from 50% which was 15 years ago to over 75%. Also, certifications have been created (energy star, no load five star rating) to force the manufacturers to ship higher quality chargers.

The resistance of a 1.5m USB cable was 1Ω, which seems quite large. This means that for 1A, the voltage drop is 1V, and so, the phone would see only 4V during charging, so the power manager limits the demanded power, increasing the required time to charge. What is more, a complete measurement of the power efficiency of the complete system should also take into consideration the cable losses. That is why, in the modern era, 3m cables are extremely rare. To my knowledge only Nokia chargers for simple phones provide such a long cable. After sale long cables also exist for smart phones, designed to have similar resistance for an increased length at a cost of ~40$.

MATLAB code to create the characteristic of a PV Panel

Photovoltaic (PV) panels are not constant voltage, current or power sources, but their output depend on the temperature or irradiance levels as well as on their connected load. This is why the power electronics converters connected on the output of the panel do not operate at a particular point, but are actively taking various measurements in order to determine which is the Maximum Power Point (MPP). The implemented algorithms can perform electrical measurements (i.e. voltage and current of the module) or environmental measurements (i.e. irradiance and temperature). The system designer needs to know the PV characteristic in order to specify the current and voltage limits of the power converter and how this will vary depending on the environmental conditions. PV suppliers always provide a PV characteristic for a nominal temperature of 25C and various irradiance levels (typically 1000W/m2, 800W/m2 and 600W/m2). They also provide temperature coefficient factors, which describe the effect of the temperature value to power output. However, since the photovoltaic phenomenon is accurately mathematically described, based on those equations, the PV characteristic can be derived for any irradiance or temperature value. The "Khouzam model" provides equations to produce such a characteristic based on parameters that are available by the PV manufacturers through their datasheet. So, a MATLAB program was created in order to implement the Khouzam model. The figure below shows the output characteristic of a MODULTEQ MTS180M-24V 180W panel for three different irradiance levels, namely 1000W/m2 (magenta), 800W/m2 (red) and 600W/m2 (blue). The effect of the irradiance level is clearly shown. The maximum PV output power decreases as the irradiance level decreases. What is more, the maximum (short circuit) current level deviation is more significant than the one of the maximum (open circuit) voltage.

A second figure shows the effect of the temperature on the PV panel output. The irradiance level is constant at 1000W/m2 but the PV panel temperature is 0C (magenta), 25C (red) and 60C (blue). This figure shows that when the temperature of the panel rises, the output power decreases. That is why cooling tubes that run on the back of the panels exist on certain installations. As the temperature rises the open circuit voltage decreases, whereas the short circuit current is not affected.

The full project of the Khouzam equations on MATLAB can be found on my Github page.

More TC74 programming on an STM32: Using sleep mode for low power

Previous posts showed how to use a TC74 temperature sensor with an STM32 microcontroller and how to handle communication errors . Since typically the temperature is not a value that changes rapidly, it is not essential to take multiple measurements with a high sampling rate, even if the I2C protocol is rather quick. For this reason, the TC74 sensor has a very low power standby mode when it not needed. The TC74 has an internal analog to digital converter which saves the value on an internal register. What is more this converter has a typical sampling rate of 8 samples per second. In standby mode this ADC is switched off. Concerning the power consumption, the information on the datasheet is a bit confusing. The datasheet provides a current consumption of 200uA in operating mode and 5uA in standby mode, which is a very significant difference. However, consumption in normal mode is measured for Vdd of 5.5V, whereas consumption in standby mode for Vdd of 3.3V. Based on my measurements of 2 TC74 operating in 3V, standby mode: 4uA, operating mode: 170uA. So indeed, the power saving is significant and should be used in low power applications. As it was analyzed, the TC74 has an 8-bit register which stores the temperature value. It has a second register (address 0x01), called the configuration register which has two bits. The first one (bit 7) enables the standby mode, whereas the second one (bit 6) shows when the sensor is ready to transmit the first data after entering operating operating. So the sequence to read the temperature using low power consumption is the following:

  1. Wake up
  2. Wait for the data to be ready (either using a delay or be polling the data ready bit of the config register
  3. Get temperature
  4. Sleep

After a wake up instruction, the TC74 needs about 300ms to transmit the first data. So in my implementation, a timer is used to wait for 500ms after a wake up instruction, get temperature and sleep the sensor and wait for 5s until the temperature is measured again. First of all, the TC74_Read_Temperature() function needs to be modified in order to read the 0x00 register (temperature) or the 0x01 register (configuration).

int TC74_Read_Register(uint8_t TC74address, uint8_t reg)

{

int8_t data1, data2;
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0) 
{ 
return -127; 
} 
if(I2C_write(I2C1, reg)>0) 
return -127; 
if(I2C_stop(I2C1)==1) 
return -127; 
if(I2C_start(I2C1, TC74address, I2C_Direction_Receiver)>0) 
{ 
return -127; 
} 
data1 = I2C_read_ack(I2C1); 
data2 = I2C_read_nack(I2C1); 
return data1; 
}



We need to have a status variable which will show whether the TC74 is in operating or standby mode.

typedef enum {TC74_SLEEPING, TC74_WAITING} TC74_statetypedef; 
TC74_statetypedef Temp_read_status=TC74_SLEEPING;



Two new functions are added, one that wakes up the sensor and another one that sends the instruction to enter standby mode.

int TC74_WakeUp(uint8_t TC74address) 
{ 
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0) 
{ 
return -127; 
} 
if(I2C_write(I2C1, 0x01)>0) 
return -127; 
if(I2C_write(I2C1, 0x00)>0) 
return -127; 
if(I2C_stop(I2C1)==1) 
return -127; 
return 0; 
} 
int TC74_Sleep(uint8_t TC74address) 
{ 
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0) 
{ 
return -127; 
} 
if(I2C_write(I2C1, 0x01)>0) 
return -127; 
if(I2C_write(I2C1, 0x80)>0) 
return -127; 
if(I2C_stop(I2C1)==1) 
return -127; return 0; 
}



After that we need to initialize a timer, TIM6 for the current example. The APB1 peripheral clock is 32MHz for the STM32L152.

void TIM6_Config(void) 
{ 
TIM_TimeBaseInitTypeDef timerInitStructure; 
NVIC_InitTypeDef NVIC_InitStructure; 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); 
timerInitStructure.TIM_Prescaler=1000; 
timerInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 
timerInitStructure.TIM_Period=32000; 
timerInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
TIM_TimeBaseInit(TIM6, &timerInitStructure); 
TIM_Cmd(TIM6, ENABLE); 
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
NVIC_Init(&NVIC_InitStructure); 
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); 
}


The interrupt handler routine of TIM6 is:

void TIM6_IRQHandler(void) 
{ 
if (TIM_GetFlagStatus(TIM6, TIM_IT_Update)!=RESET) 
{ 
TIM_Cmd(TIM6, DISABLE);
if (Temp_read_status==TC74_SLEEPING) 
{ 
TC74_WakeUp(TC74_ADDRESS); 
TIM6->PSC = 5000; 
Temp_read_status=TC74_WAITING; 
} 
else 
{ 
Temperature=TC74_Read_Register(TC74_ADDRESS,0x00); 
TC74_Sleep(TC74_ADDRESS); 
TIM6->PSC = 500; 
Temp_read_status=TC74_SLEEPING; 
} 
TIM6->CNT=0; 
TIM_Cmd(TIM6, ENABLE); 
TIM_ClearITPendingBit(TIM6, TIM_IT_Update); 
} 
}

The full project to read the temperature from the TC74 sensor with error handling and standby mode can be found on my Github page.

More TC74 on STM32: Avoiding I2C bus failure when TC74 doesn't respond

On a previous post, the code to implement the I2C protocol for an STM32 microcontroller connected to an TC74 temperature sensor was implemented. However, what happens if no TC74 is connected or due to a failure does not respond. Since the TC74 sensor will be used on the UPSat mission, the microcontroller needs to be able to acknowledge that the sensor does not respond and continue with executing the main program.

One peripheral that can be used in case the TC74 doesn't respond is the watchdog counter. If no error handling is implemented on the I2C communication, the program enters into a deadlock. The watchdog's purpose is to reset the microcontroller if it doesn't reset the watchdog counter after a short period of time, acting as an auto reset. The STM32 micro controllers include independent and window watchdogs. However, on the next time that the temperature sensor will be called again, the microcontroller will freeze again. Of course, a "reset reason" detection code could be implemented and disable TC74 communication after a reset caused to an I2C error, but the damage to the procedure execution could already be done because of the reset.

A more correct way is to implement error handling on the I2C communication and continue code execution when an error is detected, discarding the measurement. The microcontroller after sending a message through the I2C bus waits for the peripheral to respond. If the peripheral does not respond, the code execution freezes at this point. The simplest solution is to implement a timeout function, meaning that if the peripheral does not respond after a certain amount of time, the code execution will continue. The I2C peripheral on the STM32 microcontroller does not implement a timeout support inherently. However, the System Management Bus (SMBus) mode can be used which implements timeout detection. So, on the initialization function of the I2C peripheral, the I2C_mode needs to be set to I2C_Mode_SMBusHost. Then, using the I2C Timeout flag or the I2C Timeout interrupt, the error can be handled.

Furthermore, another error that can appear is an acknowledge failure. This exists when the microcontroller sends a message to the device, awaits for an acknowledge bit on the next clock but it doesn't respond. Again, the Acknowledge Failure (AF) flag can be polled to detect the error.

So based on the above, the communication protocol functions are rewritten to return 0 is the communication is good and >0 if there is an error. The main function finally returns the temperature, or -127 in case of an error:

int TC74_Read_Temperature(uint8_t TC74address)
{
int8_t data1, data2;
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0) {
I2CBus_Reset();
return -127;
}
if(I2C_write(I2C1, 0x00)>0) return -127;
if(I2C_stop(I2C1)==1) return -127;

if(I2C_start(I2C1, TC74address, I2C_Direction_Receiver)>0) {
I2CBus_Reset();
return -127;
}
data1 = I2C_read_ack(I2C1);
data2 = I2C_read_nack(I2C1);

return data1;
}

So the modification that is implemented is inside the while statement to avoid the infinite loop. If an error flag is set, the code execution is stopped, returning the error code.

int I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction)
{
int i2c_timeout=I2CTIMEOUT;
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

I2C_GenerateSTART(I2Cx, ENABLE);

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_TIMEOUT)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_TIMEOUT);
return 1;
}
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return 2;
}
}
I2C_Send7bitAddress(I2Cx, address, direction);

if (direction== I2C_Direction_Transmitter) {
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_TIMEOUT)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_TIMEOUT);
return 1;
}
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return 2;
}
}
}

else if(direction == I2C_Direction_Receiver) {
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_TIMEOUT)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_TIMEOUT);
return 3;
}
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return 4;
}
}
}
return 0;
}
int I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
I2C_SendData(I2Cx, data);

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_TIMEOUT)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_TIMEOUT);
return 1;
}
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return 2;
}
}
return 0;
}
int I2C_stop(I2C_TypeDef* I2Cx)
{
I2C_GenerateSTOP(I2Cx, ENABLE);
return 0;
}
int8_t I2C_read_ack(I2C_TypeDef* I2Cx)
{
int8_t data;

I2C_AcknowledgeConfig(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)){
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_TIMEOUT)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_TIMEOUT);
return -127;
}
if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
return -127;
}
}
data=I2C_ReceiveData(I2Cx);

return data;
}
int8_t I2C_read_nack(I2C_TypeDef* I2Cx)
{
uint8_t data;

I2C_AcknowledgeConfig(I2Cx, DISABLE);
I2C_GenerateSTOP(I2Cx, ENABLE);

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)){
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_TIMEOUT)!=RESET) {
I2C_ClearFlag(I2Cx, I2C_FLAG_TIMEOUT);
return -127;
}
}
data=I2C_ReceiveData(I2Cx);

return data;
}

The full project to read the temperature from the TC74 sensor with error handling can be found on my Github page.