jbrazio / ardufocus

:telescope: The most accurate Open Source focus controller
https://ardufocus.com
GNU General Public License v3.0
53 stars 19 forks source link

Switch for in/out focusing #5

Closed opossome closed 5 years ago

opossome commented 5 years ago

Hi !

Can you add support for 2 switchs doing in and out focusing , usefull for regular stargazing without loosing home and preset . Actually using a basic sketch with switchs on D2 and D3 and fixed speed @ 300 steps/s . Adjustable speed will be great too , like long press --> increase speed and impulse for fine tuning .

Thx for your great job !

Ultimaboot commented 5 years ago

I to find this a great idea. Is there any progress in code develpment and schematic wiring? Is it possible to use it together with your project?

jbrazio commented 5 years ago

Hi @Ultimaboot I've added new features on the board revision I'm working on that will allow plug-able modules such as this one. The version you have it will require some patchwork but it's also doable.

2019.05-rev1

I usually have the focuser box attached to the telescope itself, if the buttons are built-in then it would mean that pressing them would create oscillations.

Should this be a wired module or a built-in feature ? I'm really open to suggestions.

Ultimaboot commented 5 years ago

You could make a small control box with two buttons and connect this to the main box. The connection on the main box could be RJ jack connection or something else. Or you could intergrate it on the main box. The speed could be adjustable with a pot or with fixed speed. Dit you also consider controlling the buttons with Bluetooth (hc module) and smartphone?

Ultimaboot commented 5 years ago

I asome that the pcb modification has something the do with a display module and possible a HC module, correct?

jbrazio commented 5 years ago

Indeed.. it can be used for an ESP (wireless), Bluetooth or the HC we are starting to design.

As we need the serial to be used by the USB port the HC could be done using the I2C protocol.. the overhead is adding another nano/mini to the HC itself.

I'm thinking instead of a pot add a small OLED display and maybe a three button interface ?

We let the user define three "speeds":

Like one click makes the motor move 5 steps into one direction, double click moves 50 steps and long press moves until you release it.

The third button would be use to allow the navigation on the menu items so the user can define the speeds and so without requiring a computer.

The connection between the HC and the focuser could be either wired (four way cable) or some kind of RF/Bluetooth.

What do you think ?

Ultimaboot commented 5 years ago

Would be only a HC-05 Bluetooth module with smartphone control be a option. There something like MIT App Inventor where can simply can make control functions like the one you mentions. No LED display/interface would be needed and i think it would be cheaper too. What do you think?

jbrazio commented 5 years ago

Oh wait I read “HC” has in Hand Controller !

Yes that the Bluetooth module would go there directly, maybe with some 5V to 3.3V level shifter logic that some need.

But the problem já still there, either you have a focuser for visual or for automatic focus, because we only have one serial and we cannot use it for USB serial and Bluetooth serial.

Nevertheless I will check your App Inventor suggestion because it can indeed be useful. The only method I used before was React Native to code to both android and iOS in one go.

Ultimaboot commented 5 years ago

There is something like Software Serial Library witch make it possible to make a second serial port. https://www.arduino.cc/en/Reference/SoftwareSerial https://youtu.be/o-YVvxYiSuk But i also find that its not necessary to use both visual focus and automatic focus at the same time. What do you think?

jbrazio commented 5 years ago

@Ultimaboot actually that's a good idea but in order for it to function properly I need to assign a hardware interrupt pin to the Serial RX, none is available right now but the board can be rerouted.

I was also thinking about power, the 5V rail is getting over crowded for the little LDO on the Nano board, maybe the headers should break-out +12V and then the module board has it's own on-board 5V LDO.

But first I think we need to close this ticket which means a wired hand controller for Ardufocus.

Ultimaboot commented 5 years ago

Oke, for your information i can not close this issue.

jkoenig72 commented 5 years ago

Hi,

Same issue. Want to control the Focuser with 2 buttons.

How can I add this functionality to the existing sketch?

Thanks! Joerg

jkoenig72 commented 5 years ago

I started a bit on this -

for ardufocus.cpp added: 2 ditital pins, 2 and 3 to get buttons movement detected:

...

for(;;) 
  { 

    int button1State = digitalRead(2);
    int button2State = digitalRead(3);
    int sensorValue = analogRead(A2);
    uint32_t motorspeed = map(sensorValue, 0, 1023, 1, 255);

    comms.receive(button1State, button2State, 125 , 125); 

 }

  // Someone made an Opsie !
  // Code should not reach this
  return 0;
}

....

I added a few parameters to the comms.receive function, state of both buttons and the value from a potentiometer.

Within the moonlite.h I then parse those values through:

...

void receive(int forward, int backward, uint32_t motorspeed, int moving) 
    {

      char str[CMD_MAX_LEN];

      if(serial::receive(str)) { parse(str, forward, backward, motorspeed, moving); }

    }
...

and in the parse function, I handle the input, change motor position.

void parse(char* const str, int forward, int backward, uint32_t motorspeed, int moving) 
    {

...
if (forward == 1)
      {
        digitalWrite(4, 1);
        uint32_t pos = motor_get_position(motor);
        uint32_t old_motorspeed = motor_get_speed(motor);

        /*if (difference < 500)
          pos = pos + 5;
        */  
        pos = pos - moving;
        motor_set_target(motor, pos);
        motor_set_speed(motor, motorspeed);
        motor_start(motor);
        while (motor_is_moving(motor))
          true;
        motor_set_speed(motor, old_motorspeed);

        oldtime = curtime;
      }
      else
        digitalWrite(4, 0);

      if (backward == 1)
      {
        digitalWrite(5, 1);
        uint32_t pos = motor_get_position(motor);
        uint32_t old_motorspeed = motor_get_speed(motor);

       /* if (difference < 500)
          pos = pos + 5;
        else 
          pos = 0;
         */ 
        pos = pos + moving;
        motor_set_target(motor, pos);
        motor_set_speed(motor, motorspeed);
        motor_start(motor);
        while (motor_is_moving(motor))
          true;
        motor_set_speed(motor, old_motorspeed);

        oldtime = curtime;
      }
      else
        digitalWrite(5, 0);
...

ditital pin 4 and 5 are for LEDS, showing the direction.

jkoenig72 commented 5 years ago

The analog input is not working but with fixed values, it seems to work.

Any idea how I can add another analog input working?

jbrazio commented 5 years ago

Hi @jkoenig72 thanks for your interest on this topic ! I understand that you want to have two buttons (back and fwd) and one pot to define the speed of movement.

I have a few comments: 1) I do agree with the reading of the buttons on the main loop while 2) I would prefer to create a new class to handle the user interface, using the serial port class too handle UI works but it's not the best approach. Nevermind the class thing as refactoring can always be done at the end. 3) You should use IO::write(pin, state) instead of digitalWrite() 4) This is a blocking function while (motor_is_moving(motor)) true;

analogRead() is not implemented this is why it's not working for you. The class analog.h must be changed in order to support this. I can take care of this part.

On the main loop you check for the state of the buttons and you should also manipulate the position of the motor, no need to go into the comms.parse().

  // --------------------------------------------------------------------------
  // Loop routine -------------------------------------------------------------
  // --------------------------------------------------------------------------
  for(;;)
  {
    comms.receive();

    // Select the motor
    motor_t motor = MOTOR_ONE;

    // Get button state
    bool button1State = (bool)IO::read(2); // fwd
    bool button2State = (bool)IO::read(3); // back

    // Visual feedback
    IO::write(4, button1State);
    IO::write(5, button2State);

    // this is not working, use a fixed value for now
    //int sensorValue = analogRead(A2);
    int sensorValue = 10;

    int steps = map(sensorValue, 0, 1023, 1, 255);

    // If any of the buttons is pressed
    // maybe add a button debounce routine here
    if(button1State || button2State)
    {
      uint32_t pos = motor_get_position(motor);
      // we should not manipulate the speed of the motor, we manipulate
      // instead the number of steps per "tick"
      pos += (button1State) ? steps : (-steps);
      motor_set_target(motor, pos);
      motor_start(motor);
    }
  }

  // Someone made an Opsie !
  // Code should not reach this
  return 0;
}

This is untested code, it's just as an example. You may need to add #include "api.h" in ardufocus.h. By changing the sensorValue the motor should move different amounts per tick, so with a low value a press of a button will move let's say 5 steps and with an higher value one press on the button will move 100 steps.

jkoenig72 commented 5 years ago

Super - thanks, I will give it a try.

jkoenig72 commented 5 years ago

Super - gets moving. It will be a nice little hand controller. I will post a picture when I have done a prototype.

One thing: the motor moves when I release the button - a more natural behaviour would be: as long I have pressed the motor moves with speed increases when I release it should quickly stop.

How to do something like that?

jkoenig72 commented 5 years ago

Also, any hint how I can get analog reading for the potentiometer? :-)

Thanks!

jbrazio commented 5 years ago

For the pot, let me work a bit on it tonight I don't have time right now to tackle it.

The buttons are being treated as "one action" buttons and not "press and hold", for me this makes more sense due to type of motor we are using, a stepper measures distance in steps, has a max default speed and uses a acceleration profile to reach that speed. So the pot will set the distance the motor will travel after one click on the button.

The only way to behave like you're describing is to manipulate the "speed divider" of the motor like you're doing before, try this out:

  // --------------------------------------------------------------------------
  // Loop routine -------------------------------------------------------------
  // --------------------------------------------------------------------------
  for(;;)
  {
    comms.receive();

    // Select the motor
    motor_t motor = MOTOR_ONE;
    static int old_motor_speed = 0;

    // Get button state
    bool button1State = (bool)IO::read(2); // fwd
    bool button2State = (bool)IO::read(3); // back

    // Visual feedback
    IO::write(4, (button1State) ? HIGH : LOW);
    IO::write(5, (button2State) ? HIGH : LOW);

    // maybe add a button debounce routine here

    // If any of the buttons is pressed
    if(button1State || button2State)
    {
      // this is not working, use a fixed value for now
      //int sensorValue = analogRead(A2);
      int sensorValue = 10;

      // It's important that the "steps" value not to be lower
      // than 2, because at the stepper tick routine it will be
      // devided by two.
      int new_motor_speed = map(sensorValue, 0, 1023, 2, 255);

      // Stores the current motor speed
      if(old_motor_speed == 0)
      {
        old_motor_speed = motor_get_speed(motor);
        motor_set_speed(motor, new_motor_speed);
      }

      uint32_t pos = motor_get_position(motor);
      // Keep the motor moving without acceleration control
      pos += (button1State) ? (ACCEL_MIN_STEPS -1) : (-(ACCEL_MIN_STEPS -1));
      motor_set_target(motor, pos);
    }
    else
    {
      motor_stop(motor);
      motor_set_speed(motor, old_motor_speed);

      // Reset the stored motor speed
      old_motor_speed = 0;
    }
  }

  // Someone made an Opsie !
  // Code should not reach this
  return 0;
}

I also moved this bit bellow after the button press guard in order to save some cycles during normal operation.

      // this is not working, use a fixed value for now
      //int sensorValue = analogRead(A2);
      int sensorValue = 10;

      // It's important that the "steps" value not to be lower
      // than 2, because at the stepper tick routine it will be
      // devided by two.
      int new_motor_speed = map(sensorValue, 0, 1023, 2, 255);

Once again, this is untested code.

jkoenig72 commented 5 years ago

Ahhh... yes, that will do it. I will try it tonight.

Brilliant project you have here... :)

Thanks for helping out so quickly

jbrazio commented 5 years ago

Thanks ! I have found a bug [or a feature] on my last code block, once the motor starts moving turning the pot to adjust speed will be ignored until the button is released.

jkoenig72 commented 5 years ago

Yes... as you mentioned it. Ok - thanks. Doing the soldering right now...

jkoenig72 commented 5 years ago

IMG_0361 IMG_0362 IMG_0363 IMG_0364 IMG_0365 IMG_0366

jkoenig72 commented 5 years ago

Did 3 of them. Plan is to use them with odroid xu4 with Ekos / Indi. Fully controlled scope. Lets see... :-)

jbrazio commented 5 years ago

Very nice ! I had a go at changing analog.h and it’s almost done. Just an important remark for the pot, it needs to get its VCC from the ARef pin (1.1V) otherwise it will saturate sooner than expected.

jkoenig72 commented 5 years ago

Hmmm ... this speed increase seems not to work this way ... no movement at all.

  if (button1State || button2State)
  {
      int sensorValue = 512;

      int new_motor_speed = map(sensorValue, 0, 1023, 2, 255);

      if (old_motor_speed == 0)
      {
          old_motor_speed = api::motor_get_speed(motor);
          api::motor_set_speed(motor, new_motor_speed);
      }

      uint32_t pos = api::motor_get_position(motor);

      //pos += (button1State) ? (ACCEL_MIN_STEPS - 1) : (-(ACCEL_MIN_STEPS - 1));
      pos += 50;
      api::motor_set_target(motor, pos);
      api::motor_start(motor);
  }
  else
  {
      api::motor_stop(motor);
      api::motor_set_speed(motor, old_motor_speed);

      // Reset the stored motor speed
      old_motor_speed = 0;
  }
jkoenig72 commented 5 years ago

This one works very nicely - however, that the method you suggested...

for(;;) { comms.receive();

  // Select the motor
  motor_t motor = MOTOR_ONE;

  // Get button state
  bool button1State = (bool)IO::read(2); // fwd
  bool button2State = (bool)IO::read(3); // back

  // Visual feedback
IO::write(4, (button1State) ? HIGH : LOW);
IO::write(5, (button2State) ? HIGH : LOW);

  // this is not working, use a fixed value for now
  //int sensorValue = analogRead(A2);
  //int sensorValue = 512;

  int steps = 2000; //map(sensorValue, 0, 1023, 2, 2000);

  // If any of the buttons is pressed
  // maybe add a button debounce routine here
  if (button1State)
  {
      uint32_t pos = api::motor_get_position(motor);
      pos = pos + steps;
      api::motor_set_target(motor, pos);
      api::motor_start(motor);
  }

  if(button2State)
  {
      uint32_t pos = api::motor_get_position(motor);
      // we should not manipulate the speed of the motor, we manipulate
      // instead the number of steps per "tick"
      pos = pos - steps;
      api::motor_set_target(motor, pos);
      api::motor_start(motor);
  }

}

// Someone made an Opsie ! // Code should not reach this return 0; }

jbrazio commented 5 years ago

Hi @jkoenig72 I've uploaded a new branch (https://github.com/jbrazio/ardufocus/tree/ui/buttons-pot) for you to test. Check the config.h and at the end edit the settings to match your board layout.

Forward, backward and potentiometer speed set is fully functional.

jkoenig72 commented 5 years ago

Thanks - will give it a try tonight...

jkoenig72 commented 5 years ago

Did a quick test ... those setting below works very nice to me, however when I use it in combination with moonlite controller program ("Moonlite Single Focuser"), I detect that the serial communication breaks after a few seconds a button is pressed (the button in the controller Windows in the lower left corner shows "Connect" again, coming from "Disconnect").

Seems somehow the serial communication gets disrupted.

// NEMA17 motors allow you to use higher speed limits: // - Max speed: 1000 // - Min speed: 250 //

define MOTOR1_MAX_SPEED 1000

define MOTOR1_MIN_SPEED 250

// ---------------------------------------------------------------------------- // USER INTERFACE ------------------------------------------------------------- // ----------------------------------------------------------------------------

// Keys and Pot user interface

define USE_UI_KAP

define UI_KAP_FWD_BUTTON_PIN 2

define UI_KAP_BWD_BUTTON_PIN 3

// Switches are designed to be pulled-up HIGH when released and LOW when being // pushed, this directive allows you to invert this logic.

define UI_KAP_INVERT_BUTTON_LOGIC

define UI_KAP_FWD_BUTTON_LED_PIN 4

define UI_KAP_BWD_BUTTON_LED_PIN 5

// Pin A0 is channel 0 (..) pin A3 is channel 3

define UI_KAP_ADC_CHANNEL 2

...

jkoenig72 commented 5 years ago

It happens if I press one of the buttons ~ >5 sec.

jbrazio commented 5 years ago

With my prototype is working, I have no disconnects. I see you activated the inverted button logic, how are you wiring your buttons ? When you press the buttons do you see the controller program updating the position counter ?

jkoenig72 commented 5 years ago

Nothing special. 10k pulldown resistors for both buttons, connected to ground. When pressed 5v goes into D2 / D3.

digitalRead returns 0 and if pressed 1 - maybe it's the cable, I will try a few and will report back.

And yes - I can see the counter changing.

jbrazio commented 5 years ago

Other possible cause could be brownout of the AVR, which means that the 5V rail has not enough power and "restarts" the AVR.

jbrazio commented 5 years ago

New commit ccae67b84ea8398f34636ced0a1fe7d7187526d1

jbrazio commented 5 years ago

@opossome @Ultimaboot would you like to test this new feature ?

jkoenig72 commented 5 years ago

Sure. I already build a nice little test board.

I switched the motor driver and now no more serial comm errors.

Sadly I have to travel for a few days. Will do more testing on Friday but great job so far.

jkoenig72 commented 5 years ago

Anything specific you want me to do / test?

Ultimaboot commented 5 years ago

Well i have to make the hardware first before i can test it, but yes i would like to test this new feature.

jbrazio commented 5 years ago

Thanks everyone, if you find any issues please open a new ticket. I will merge this branch into the master.

holacomostas commented 5 years ago

@jkoenig72 I'm sorry, but I couldn't find a way to send you an email. Would you be so kind as to tell me where I can find the file of the focuser motor bracket that you have in the photos you have sent? Thank you in advance.

Email:anofeles@outlook.com

Pd. Very, very sorry for this off topic, jbrazio.

jkoenig72 commented 3 years ago

I have it somewhere in tinkercad. If you still need I can share, but I guess is very easy to do yourself so it exactly fits your needs. Look up nema holder or similar on thingiverse. Upload in tinkercad and apply your changes...

But let me know if you still need it - I can share.

max2206 commented 2 years ago

It happens if I press one of the buttons ~ >5 sec.

I have the same problem before i added the buttons al was working wel.

max2206 commented 2 years ago

Hi @Ultimaboot I've added new features on the board revision I'm working on that will allow plug-able modules such as this one. The version you have it will require some patchwork but it's also doable.

2019.05-rev1

I usually have the focuser box attached to the telescope itself, if the buttons are built-in then it would mean that pressing them would create oscillations.

Should this be a wired module or a built-in feature ? I'm really open to suggestions.

Any idea where we can buy teh latest PCB with the buttons

/\/\arnix