Archive for February 18th, 2015

Kenmore 158: Linearized Speed Control

Plugging the normalized pedal position into the code that turns position into speed:

case PD_RUN :
	if (PedalPosition > 5) {
		if (MotorDrive.State != RUNNING) {
			EnableMotor();
			MotorDrive.State = RUNNING;
		}

		BaseDAC.setVoltage(0x0fff,false);								// give it a solid pulse
		SampleCurrent(PIN_CURRENT_SENSE);								// sample over a half cycle
		if (DriveOnTime > CurrentSamplingTime) {
			delay(DriveOnTime - CurrentSamplingTime);
		}

// Pedal to the metal?
//   ... if so, stall here with motor drive fully on until the pedal releases

		while ((MotorDrive.SpeedRange == SPEED_HIGH) && (PedalPosition >= 100)) {
			PedalPosition = PedalPercent(ReadAI(PIN_PEDAL));
		}

		BaseDAC.setVoltage(0,false);									//  ... then turn it off

		delay(map(constrain(PedalPosition,0,PedalMaxClamp),
				0,100,
				DriveOffTime,0));
	}
	else {
		if (MotorDrive.State == RUNNING) {
			if (MotorSensor.RPM) {
				printf("Coast: %d\r\n",MotorSensor.RPM);
				delay(100);
			}
			else {
				printf("Parking ");
				ParkNeedle(MotorDrive.ParkPosition);
				MotorDrive.State = STOPPED;
				printf(" stopped\r\n");
			}
		}
	}
	break;

The magic happens in highlighted statement, which flips the sense of the pedal motion and linearly scales the result into a delay() value ranging from 120 ms (pedal barely pressed) down to 0 ms (pedal almost fully pressed). If the pedal is all the way down, then the preceding while() locks up until it’s released a bit, whereafter the delay will be nearly zero.

That sorta-kinda worked, but the user community said that the pedal response required pushing too hard for top speed: it should get faster, sooner. The problem came from the simplistic way I set the speed: it was inversely proportional to the position.

Plotting speed against pedal position shows the problem:

Speed vs pedal - period control

Speed vs pedal – period control

I figured the right approach was to make the speed vary linearly with the pedal position, so the trick was to plot the off-time delay vs. the actual speed:

Off-time delay vs speed - period control

Off-time delay vs speed – period control

The second-order equation bottles up a bunch of nonlinear things. Given that this was using the original code, I made the dubious assumption that more-or-less the same delay in the new code would produce more-or-less the same speed.

The new code discards the current-sampling routine that I was using to get a fixed delay (because I don’t need to know the current in pulse-drive mode), then used that time for the floating-point calculation required to find the off-time delay. That chunk of code took a bit of fiddling to get right:

case PD_RUN :
	if (PedalPosition > 5) {
		if (MotorDrive.State != RUNNING) {
			EnableMotor();
			MotorDrive.State = RUNNING;
		}

		BaseDAC.setVoltage(0x0fff,false);								// give it a solid pulse
		MillisOn = millis() + (unsigned long)DriveOnTime;

		TargetSpeed = (float)map(constrain(PedalPosition,0,PedalMaxClamp),
				0,100,
				0,700);						// quick and dirty 0 to 700 stitch/min range
		OffTime = (int)((1.94e-4*TargetSpeed - 0.286)*TargetSpeed + 106.0);
		OffTime = constrain(OffTime,0,120);								// clamp to reasonable range
		MillisOff = MillisOn + (unsigned long)OffTime;					// compute end of off time

		while (millis() <= MillisOn) {									// wait for end of pulse
			continue;
		}

		if ((PedalPosition >= 100) && (MotorDrive.SpeedRange == SPEED_HIGH)) {	// pedal down in full speed mode?
			printf("Full speed ... ");
			OffTime = 0;
			while (PedalPosition >= 100) {								//  ... full throttle!
				PedalPosition = PedalPercent(ReadAI(PIN_PEDAL));
			}
			BaseDAC.setVoltage(0,false);								//  pedal released, start coasting
			printf(" done\r\n");
		}
		else {															// pedal partially pressed
			BaseDAC.setVoltage(0,false);								// pulse done, turn motor off
			while (millis() <= MillisOff) {								// wait for end of off period
				continue;
			}
		}
	}

But the result looks as pretty as you could possibly expect:

Speed vs pedal - linearized speed control

Speed vs pedal – linearized speed control

The pedal still provides a soft-start transition from not moving to minimum speed, which remains an absolute requirement: having an abrupt transition to that straight line would be a Bad Thing. Fortunately, the nature of the magnet moving toward the Hall effect sensor gives you that for free.

Although we’re still evaluating the results, the user community seems happier…

, ,

4 Comments