Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ The controller uses the protocol Moonlite (as documented in the indilib project)

This is a port of an awesome code from https://github.com/Hansastro/Focuser to ESP32 platform with some additions:
1. It uses TMC2209 stepper motor driver (because it's cool and really silent).
1. It uses an optical rotary encoder connected to pins 2 and 15 as a handcontroller, which helps manually focus your telescope on a not-really-stable mounts. The encoder focusing control feels very direct and highly resolved (because it has about 1:5 reduction).
1. It uses an optical rotary encoder connected to pins 2 and 15 as a handcontroller, which helps manually focus your telescope on a not-really-stable mounts. The encoder focusing control feels very direct and highly resolved (because it has about 1:5 reduction).
1. **Variable speed encoder control** - inspired by https://github.com/semenmiroshnichenko/Superfok, the encoder now uses a logarithmic speed multiplier that adjusts the motor steps based on rotation speed. Fast encoder rotations result in more motor steps per encoder step, providing both precision for fine adjustments and speed for coarse adjustments.

# Hardware
If you want to build a focuser controller by yourself, please check out a hardware repository https://github.com/simonachmueller/ESP32Focuser-hardware
Expand Down
50 changes: 47 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const int encoderMotorstepsRelation = 5;
unsigned long timestamp;
unsigned long displayTimestamp;

// Variables for variable speed encoder handling
long lastEncoderCount = 0;
long virtualMotorPosition = 0; // Accumulated motor position with speed adjustments

//LM335 TemperatureSensor(temperatureSensorPin);
StepperControl Motor(stepPin,
directionPin,
Expand Down Expand Up @@ -166,11 +170,15 @@ void processCommand()
case ML_SN:
// Set the target position
encoder.setCount(SerialProtocol.getCommand().parameter * encoderMotorstepsRelation);
lastEncoderCount = encoder.getCount();
virtualMotorPosition = SerialProtocol.getCommand().parameter;
Motor.setTargetPosition(SerialProtocol.getCommand().parameter);
break;
case ML_SP:
// Set the current motor position
encoder.setCount(SerialProtocol.getCommand().parameter * encoderMotorstepsRelation);
lastEncoderCount = encoder.getCount();
virtualMotorPosition = SerialProtocol.getCommand().parameter;
Motor.setCurrentPosition(SerialProtocol.getCommand().parameter);
break;
case ML_PLUS:
Expand Down Expand Up @@ -220,14 +228,50 @@ void setup()
//displayTimestamp = millis();

SetupEncoder();

// Initialize tracking variables
lastEncoderCount = encoder.getCount();
virtualMotorPosition = Motor.getCurrentPosition();
}

void HandleHandController()
{
long targetPosition = Motor.getTargetPosition();
long encoderPosition = encoder.getCount() / encoderMotorstepsRelation;
Motor.setTargetPosition(encoderPosition);
if(targetPosition != encoderPosition)
long currentEncoderCount = encoder.getCount();

// Calculate encoder change since last call
long encoderDelta = currentEncoderCount - lastEncoderCount;

if (encoderDelta != 0)
{
// Calculate speed multiplier using logarithmic function similar to Superfok
// This makes fast rotations result in more motor steps per encoder step
long absEncoderDelta = abs(encoderDelta);

// Apply logarithmic scaling: log(n+1) gives smooth acceleration
// For absEncoderDelta=1: log(2)≈0.69, for 5: log(6)≈1.79, for 10: log(11)≈2.4
float speedMultiplier = log((float)(absEncoderDelta + 1));

// Calculate motor steps with speed multiplier
// Base relation * encoder change * speed multiplier
long motorSteps = (long)(encoderMotorstepsRelation * absEncoderDelta * speedMultiplier);

// Apply direction
if (encoderDelta > 0)
{
virtualMotorPosition += motorSteps;
}
else
{
virtualMotorPosition -= motorSteps;
}

// Update tracking variable
lastEncoderCount = currentEncoderCount;
}

Motor.setTargetPosition(virtualMotorPosition);
if(targetPosition != virtualMotorPosition)
{
Motor.goToTargetPosition();
}
Expand Down
Loading