bdring / FluidNC

The next generation of motion control firmware
Other
1.56k stars 379 forks source link

Problem: Inconsistent behaviour with servo motors #859

Closed Dominykasssx closed 1 year ago

Dominykasssx commented 1 year ago

Controller Board

Custom board.

Machine Description

I'm using external stepper drivers DM556. Stepper motors works fine for X, Y and Z axis. Servo does not work properly on any axis.

Input Circuits

I have 2 servo motors connected to PIN 21 and 19

Configuration file

name: "Solo robot"
board: "solo robot board"

stepping:
  engine: RMT
  idle_ms: 150
  dir_delay_us: 1
  pulse_us: 2
  disable_delay_us: 0

axes: 
  x:
    steps_per_mm: 50
    max_rate_mm_per_min: 800
    acceleration_mm_per_sec2: 100.000
    max_travel_mm: 900
    soft_limits: true
    homing:
      cycle: 1
      positive_direction: false
      mpos_mm: 150.000
      feed_mm_per_min: 150.000
      seek_mm_per_min: 500.000
      settle_ms: 500
      seek_scaler: 1.100
      feed_scaler: 1.100

    motor0:
      limit_neg_pin: gpio.13:high
      standard_stepper:
        direction_pin: gpio.27:low
        step_pin: gpio.18

  y:
    steps_per_mm: 50
    max_rate_mm_per_min: 800
    acceleration_mm_per_sec2: 100.000
    max_travel_mm: 1200
    soft_limits: true
    homing:
      cycle: 2
      positive_direction: false
      mpos_mm: 150.000
      feed_mm_per_min: 150.000
      seek_mm_per_min: 500.000
      settle_ms: 500
      seek_scaler: 1.100
      feed_scaler: 1.100

    motor0:
      limit_neg_pin: gpio.34:high
      standard_stepper:
        direction_pin: gpio.25:low
        step_pin: gpio.26

  z:
    steps_per_mm: 80
    max_rate_mm_per_min: 2000
    acceleration_mm_per_sec2: 100.000
    max_travel_mm: 150
    soft_limits: true
    homing:
      cycle: 3
      positive_direction: false
      mpos_mm: 150.000
      feed_mm_per_min: 150.000
      seek_mm_per_min: 500.000
      settle_ms: 500
      seek_scaler: 1.100
      feed_scaler: 1.100

    motor0:
      limit_neg_pin: gpio.39:high
      standard_stepper:
        direction_pin: gpio.32:low
        step_pin: gpio.33

  a:
    steps_per_mm: 100.000
    max_rate_mm_per_min: 5000.000
    acceleration_mm_per_sec2: 100.000
    max_travel_mm: 5.000
    soft_limits: true
    homing:
      cycle: 1
      positive_direction: true
      mpos_mm: 5.000

    motor0:
      rc_servo:
        pwm_hz: 50
        output_pin: gpio.19
        min_pulse_us: 1000
        max_pulse_us: 2000

  b:
    steps_per_mm: 100.000
    max_rate_mm_per_min: 5000.000
    acceleration_mm_per_sec2: 100.000
    max_travel_mm: 5.000
    soft_limits: true
    homing:
      cycle: 1
      positive_direction: true
      mpos_mm: 5.000

    motor0:
      rc_servo:
        pwm_hz: 50
        output_pin: gpio.21
        min_pulse_us: 1000
        max_pulse_us: 2000

Startup Messages

rst:0xc (SW_CPU_RESET),boot:0x16 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:12812
load:0x40080400,len:3032
entry 0x400805e4

[MSG:INFO: FluidNC v3.6.8]
[MSG:INFO: Compiled with ESP32 SDK:v4.4.1-1-gb8050b365e]
[MSG:INFO: Local filesystem type is spiffs]
[MSG:INFO: Configuration file:solo1.yaml]
[MSG:INFO: Machine Solo robot]
[MSG:INFO: Board solo robot board]
[MSG:INFO: Stepping:RMT Pulse:2us Dsbl Delay:0us Dir Delay:1us Idle Delay:150ms]
[MSG:INFO: Axis count 5]
[MSG:INFO: Axis X (150.000,1050.000)]
[MSG:INFO:   Motor0]
[MSG:INFO:     standard_stepper Step:gpio.18 Dir:gpio.27:low Disable:NO_PIN]
[MSG:INFO:  X Neg Limit gpio.13]
[MSG:INFO: Axis Y (150.000,1350.000)]
[MSG:INFO:   Motor0]
[MSG:INFO:     standard_stepper Step:gpio.26 Dir:gpio.25:low Disable:NO_PIN]
[MSG:INFO:  Y Neg Limit gpio.34]
[MSG:INFO: Axis Z (150.000,300.000)]
[MSG:INFO:   Motor0]
[MSG:INFO:     standard_stepper Step:gpio.33 Dir:gpio.32:low Disable:NO_PIN]
[MSG:INFO:  Z Neg Limit gpio.39]
[MSG:INFO: Axis A (0.000,5.000)]
[MSG:INFO:   Motor0]
[MSG:INFO:     rc_servo Pin:gpio.19 Pulse Len(1000,2000 period:1048575)]
[MSG:INFO: Axis B (0.000,5.000)]
[MSG:INFO:   Motor0]
[MSG:INFO:     rc_servo Pin:gpio.21 Pulse Len(1000,2000 period:1048575)]
[MSG:INFO: Kinematic system: Cartesian]
[MSG:INFO: Using spindle NoSpindle]
[MSG:INFO: STA SSID is not set]
[MSG:INFO: AP SSID FluidNC IP 192.168.0.1 mask 255.255.255.0 channel 1]
[MSG:INFO: AP started]
[MSG:INFO: WiFi on]
[MSG:INFO: Captive Portal Started]
[MSG:INFO: HTTP started on port 80]
[MSG:INFO: Telnet started on port 23]

Grbl 3.6 [FluidNC v3.6.8 (wifi) '$' for help]
[MSG:INFO: '$H'|'$X' to unlock]

User Interface Software

WebUI

What happened?

I have a problem while trying to use RC servo motors. I want to use 2 servo motors on A and B axis. Servos are moving very weird. For example I'm moving A axis, but B axis starts to spin too sometimes.

I do not know why my servos are not working with FluidNC correctly, I'm using 12v servos and they work just fine with ESP32 and it doesn't require signal to be 0-12V or similar. I'm using external power source of 12V. Ground and Signal is connected to ESP32

Maybe my config is wrong?

I already tried to change value of idle_ms and remove it completely. Change pwm_hz, steps_per_mm. Configure those Servo motors on X, Y or Z axis. Nothing helped

Problem video: https://youtu.be/33M7h_5wbLg

Other Information

I trought maybe my servo motors are connected wrong or something bad with wiring. So I tested my servo motors with simple sketch:

#include <WiFi.h>
#include <Servo.h>

Servo myservo; 

// GPIO the servo is attached to
static const int servoPin = 21;

const char* ssid     = "SSID";
const char* password = "PASS";

WiFiServer server(80);

String header;

String valueString = String(5);
int pos1 = 0;
int pos2 = 0;

unsigned long currentTime = millis();
unsigned long previousTime = 0; 
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);

  myservo.attach(servoPin); 

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();  

  if (client) {                           
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          
    String currentLine = "";               
    while (client.connected() && currentTime - previousTime <= timeoutTime) {
      currentTime = millis();
      if (client.available()) {            
        char c = client.read();             
        Serial.write(c);                    
        header += c;
        if (c == '\n') {                   
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");

            client.println("</head><body><h1>ESP32 with Servo</h1>");
            client.println("<p>Position: <span id=\"servoPos\"></span></p>");          
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\""+valueString+"\"/>");

            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}</script>");

            client.println("</body></html>");     

            if(header.indexOf("GET /?value=")>=0) {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString = header.substring(pos1+1, pos2);

              myservo.write(valueString.toInt());
              Serial.println(valueString); 
            }         
            client.println();
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') { 
          currentLine += c; 
        }
      }
    }
    header = "";
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

And it worked just fine without any lagging or delay.

Video: https://youtube.com/shorts/PDRU53byrSg

So what can be wrong with my configuration?

bdring commented 1 year ago

Try changing idle_ms to 255

Dominykasssx commented 1 year ago

Try changing idle_ms to 255

Already tried. didn't helped.

Here is video: https://youtu.be/33M7h_5wbLg

bdring commented 1 year ago

Was the video taken with idle_ms: 255 ?

Dominykasssx commented 1 year ago

Video was taken with idle_ms: 150. But I already tested and testing now with 255.

Not really understand what happining... Sometimes I try to move A or B axis, and X, Y or Z starts to move. Why?

Video WebUI example: https://youtu.be/SiKnWTKoyTk

bdring commented 1 year ago

Can you send a photo of your controller?

Dominykasssx commented 1 year ago

Sorry for bad quality photo.

All axis including servo is directly connector to therminals. No filter is used. 341054147_2057497714446260_8237773181723343660_n

Dominykasssx commented 1 year ago

Servo and stepper motors pinout

image

S1 - Servo1 S2 - Servo2

Prelo96 commented 1 year ago

The stepper drivers went creazy couse the low voltage of the logic, dm556 need 4/5V mininum for the logic. U need to amplify the dir ena and pulse signals from 0÷3.3V to 0÷5V

bdring commented 1 year ago

Thanks for letting me know that. My test is easier if use a 6 pack and an RC Servo module. That uses I2SO_Stream steps instead of your RMT.

It sounds like the steppers motors are not related to this issue.

I just tested about 100 moves on A and it never caused B to move. Same with B moves.

Can you compile and load the the devt branch? It allows you to set the servo update interval with a timer_ms: setting. The default is 75, but 20 would be better for servos.

    motor0:
      rc_servo:
        pwm_hz: 50
        output_pin: gpio.4
        min_pulse_us: 1000
        max_pulse_us: 2000
        timer_ms: 20
MitchBradley commented 1 year ago

The stepper drivers went creazy couse the low voltage of the logic, dm556 need 4/5V mininum for the logic. U need to amplify the dir ena and pulse signals from 0÷3.3V to 0÷5V

This could be true but it is not necessarily true. Many optocouplers are much more sensitive than their guaranteed ratings. I have driven optocoupled steppers from 3.3V with great success.

The low value (2) for pulse_us could also be the problem. There is no advantage to using a short pulse, because the fastest axis only moves at 2000 mm/min * 80 steps/mm / 60 sec/min = 2667 steps/sec, or 375 us/step.

Another possible concern is the use of AP mode for the WiFi. That is a known source of issues due to memory problems in the Espressif AP code. We recommend using AP mode only for initial setup. To eliminate this as a contributor to the problem, please either switch to STA mode or turn off the radio.

Dominykasssx commented 1 year ago

I compiled it and tested. It looks like it works much better.

But... I get some weird coordinates when jogging. Am I doing something wrong?

  1. Homing A and B axis
  2. Jogging -10 with A axis and machine coordinate shows -1.713
  3. Then pressing +1 and machine coordinate changes to -4

https://user-images.githubusercontent.com/50581706/231858933-86dcac92-2f61-4166-89cb-c3b984a39e4c.mp4

MitchBradley commented 1 year ago

You have soft limits set, with an A axis range of 0..5 mm. Jogging by -10 is not going to work.

MitchBradley commented 1 year ago

What probably happened was that there is a work coordinate offset so +5 in machine coordinates is 0 in work coordinates and 0 in machine coordinates is -5 in work coordinates. When you tried to jog to -10, the jogging code truncated that to stay within the machine range of 0..5 (work -5..0). The jog ended up at -5, but the ending position of -5 did not get reported because you hit the +1 jog before the final report was issued; the -1.713 was an interim report. Then the +1 jog went from -5 to -4.

MitchBradley commented 1 year ago

Well, according to the display, there is no WCO offset - but it is possible that the UI has not picked up on that offset yet. There could be a glitch in the auto reporting. The offset field is not issued in every report, per longstanding GRBL behavior.

Dominykasssx commented 1 year ago

The stepper drivers went creazy couse the low voltage of the logic, dm556 need 4/5V mininum for the logic. U need to amplify the dir ena and pulse signals from 0÷3.3V to 0÷5V

This could be true but it is not necessarily true. Many optocouplers are much more sensitive than their guaranteed ratings. I have driven optocoupled steppers from 3.3V with great success.

The low value (2) for pulse_us could also be the problem. There is no advantage to using a short pulse, because the fastest axis only moves at 2000 mm/min * 80 steps/mm / 60 sec/min = 2667 steps/sec, or 375 us/step.

Another possible concern is the use of AP mode for the WiFi. That is a known source of issues due to memory problems in the Espressif AP code. We recommend using AP mode only for initial setup. To eliminate this as a contributor to the problem, please either switch to STA mode or turn off the radio.

Well the stepper motors are working great with my setup. Only sometimes it gets crazy and starts to move randomly when servo axis is moved. I think it could be because the voltage drops and the pin becomes floating between HIGH and LOW, but I use external power source for servo motors, and only GND and signal is connected to ESP32, so voltage should not drop when I move servo axis.

Let's say the voltage drops too much causing stepper motors vibrate and move in random direction, in which case FluiNC wouldn't know and wouldn't display the changed coordinates, right? But coordinates changes - so is this is a software bug?

MitchBradley commented 1 year ago

What happens if you disconnect the power to the servos?

bdring commented 1 year ago

If you only move an RC Servo and the stepper moves and reports that it has moved it would be a bug. The only thing that connects axes together is kinematics and cartesian doesn't do any of that. We have never seen that in any rev of the firmware.

Can you do your testing with FluidTerm. It is hard to follow what you are doing in the WebUI. Manually request status before and after moves. Show the offsets with $#.

Dominykasssx commented 1 year ago

Okay, so I connected my ESP to my local network.

Maybe my homing configuration is still wrong?

  1. I home the machine
  2. I move A-1
  3. X, Y and Z goes to 150, 150, 150.

This is maybe because of mpos_mm: 150.000 is set on X, Y and Z axis?

Not FluidTerm, but webui terminal by manually writing commands:

[MSG:INFO: '$H'|'$X' to unlock]
$H
ok
<Idle|MPos:0.000,0.000,0.000,5.000,5.000|FS:0,0|WCO:0.000,0.000,0.000,0.000,0.000>
$#
[G54:0.000,0.000,0.000,0.000,0.000]
[G55:0.000,0.000,0.000,0.000,0.000]
[G56:0.000,0.000,0.000,0.000,0.000]
[G57:0.000,0.000,0.000,0.000,0.000]
[G58:0.000,0.000,0.000,0.000,0.000]
[G59:0.000,0.000,0.000,0.000,0.000]
[G28:0.000,0.000,0.000,0.000,0.000]
[G30:0.000,0.000,0.000,0.000,0.000]
[G92:0.000,0.000,0.000,0.000,0.000]
[TLO:0.000]
ok
G91 G21 F500 A-1
ok
<Jog|MPos:2.480,2.480,2.475,4.980,5.000|FS:500,0|Ov:100,100,100>
?
<Idle|MPos:150.000,150.000,150.000,4.000,5.000|FS:0,0>
$#
[G54:0.000,0.000,0.000,0.000,0.000]
[G55:0.000,0.000,0.000,0.000,0.000]
[G56:0.000,0.000,0.000,0.000,0.000]
[G57:0.000,0.000,0.000,0.000,0.000]
[G58:0.000,0.000,0.000,0.000,0.000]
[G59:0.000,0.000,0.000,0.000,0.000]
[G28:0.000,0.000,0.000,0.000,0.000]
[G30:0.000,0.000,0.000,0.000,0.000]
[G92:0.000,0.000,0.000,0.000,0.000]
[TLO:0.000]
ok
bdring commented 1 year ago

The thing that is a little odd with your config is the range. On X it is (150 to 1050). I would have to see your current x axis config to fully explain it.

Send $axes/x to see the full config for X.

The negative homing and soft limits could create a weird edge case that is not handled right. It should home and set the mpos to 150, but it is setting it to 0. Now you are outside the range with soft limits on.

[MSG:INFO: Axis X (150.000,1050.000)]
[MSG:INFO:   Motor0]
[MSG:INFO:     standard_stepper Step:gpio.18 Dir:gpio.27:low Disable:NO_PIN]
bdring commented 1 year ago

Also, in the future. please ? before and after each command. I need to see if the mode has returned to idle and where it thinks it is.

The "jog" status is weird too.

bdring commented 1 year ago

I have some theories to check.

  1. repost the current config file. Send $CD to get it.
  2. Send $message/level=debug to get debug messages and send $H.
MitchBradley commented 1 year ago

I have an explanation for why the soft-limit-enforced range for A and B is -5..0 instead of 0..5. It is because

  1. There are no limit switches for A and B, thus actual homing cannot be performed, and
  2. The homing cycle for A and B is set to 1. If you want homing to set mpos_mm for an axis to the value of mpos_mm , without actually performing homing motion, you must set cycle: -1 for that axis.

Edit: The above is incorrect because Servo homing works differently; it does not use limit switches, but rather moves to a fixed position.

Dominykasssx commented 1 year ago

This is what I'm trying to achieve:

  1. Simply home X, Y and Z axis to it's 0 position. For this mpos_mm should be set to 0 as I understand. Maximum travel is correct, X axis 900mm, Y axis 1200mm, Z axis 150mm.
  2. Home servo motors to 0 (in the middle), but be able to control it from -5 to 5 for example.

image

Question: I would like to calibrate servo motor that I could enter degree and it will move to that degree. As I understand step_per_mm should be changed and with that setting I should be able to get what I want. But changing step_per_mm on servo does nothing. Maybe some other option should be used on servo?

I will try my best to debug machine and will provide logs as soon as possible @MitchBradley @bdring

bdring commented 1 year ago

I will explain servo calibration after we solve the other issue.

Please provide your current config file and the log during homing.

MitchBradley commented 1 year ago

We need good data in order to debug this. In the report above, you wrote:

ok
G91 G21 F500 A-1
ok
<Jog|MPos:2.480,2.480,2.475,4.980,5.000|FS:500,0|Ov:100,100,100>
?
<Idle|MPos:150.000,150.000,150.000,4.000,5.000|FS:0,0>

The <Jog|..> status is consistent with a "$J=G91 G21 F500 A-1" command but not with a "G91 ..." command that is not preceded by "$J=". So I think you might not have provided accurate data.

The lack of complete and accurate data is wasting everyone's time.

bdring commented 1 year ago

I think we understand the problem. This is the first time we have seen it due to you doing several non standard things.

It appears you are jogging before homing all axes. You have soft limits enabled. Soft limits should not be used on any axis that has not been homed. Nothing has established the true machine location until it is homed.

You also have axes defined with a range that does not include 0. The machine turns on at 0 for each axis. The true location is not known so 0 is used. The machine starts with a soft limit issue.

There is a function to makes sure jogs are forced to work in the axis range for all axes with soft limits. This prevents accidentally jogging into a soft limit error. This is causing the unintended motion.

We are not going to change the basic behavior. We are going to add some messages and alarms. You will not be able to move any axis that has not been homed and has soft limits on.

Dominykasssx commented 1 year ago

I apologize for the reply delay.

@bdring I think you are right. I set mpos_mm to 0 on X, Y and Z axis. After homing all axis, seems that the problem gone. X, Y or Z axis does not move when controling servo A or B axis.

Are the debug logs still needed and I should gather them?

With new config problem does not occur: solo1.yaml.txt

So could you tell me how should I calibrate my servos?

bdring commented 1 year ago

You have a pulse length range and a units range. These ranges are linearly mapped to each other.

You can adjust the width of the ranges and slide them up or down.

The pulse lengths can be adjusted live. Be sure to permanently save them to the config after you get what you want.

Please check the wiki on live tuning. Also be aware the most RC servos are not as accurate or repeatable as steppers.

Dominykasssx commented 1 year ago

Thank you! I calibrate them that millimeters would be equal to degree! Nice!

What about homing servo in the middle, is it possible? @bdring

bdring commented 1 year ago

No, homing only works to ends.

Dominykasssx commented 1 year ago

It appears you are jogging before homing all axes. You have soft limits enabled. Soft limits should not be used on any axis that has not been homed. Nothing has established the true machine location until it is homed.

Okay. Servo motors does not require homing to use soft limits theoretically, because they does not have any limit switches and uses simple PWM to get to the right position.

As I understand it's not possible to use soft limits without homing servo axis now, I'm right? But it should be possible.

bdring commented 1 year ago

You do not need to home the RC Servos. You can use soft limits if you stay within the axis range. This means the range should include 0, because the machine starts at 0.