evil-mad / EggBot

Software for The Original EggBot
GNU General Public License v3.0
287 stars 140 forks source link

Add automatic limit switch feature(s) to EBB firmware #58

Closed oskay closed 4 months ago

oskay commented 8 years ago

Following up on https://github.com/techninja/cncserver/issues/81, it would be good to add some features to the EBB firmware that can automatically detect and respond to limit switches being tripped.

(It is already possible to use the digital input features in the EBB firmware to detect a limit switch being tripped, but it is necessary to poll the input. In practice, this makes it possible to move in short steps towards a limit switch for initial position homing, but it is not practical to use it to detect limit switches being tripped during normal operation.)

Possible implementations include:

EmbeddedMan commented 8 years ago

OK, I'd like to work on this functionality, to see if it can be done in a straightforward way, and get the feature into a new EBB firmware version.

So, thinking about it a bit more, I honestly like the third idea you have there, with the CS command. I'm not quite understanding why there could be up to 8 active at once though - wouldn't it just be four? (one in each direction, for each of two motors)

What happens when one limit switch is tripped while both motors are moving? Do both motors stop? (That seems to be the required action in mixed geometry machines.)

And just to be clear, we are thinking of looking for edges on the limit switches as the mechanism for triggering the EStop, correct? In other words, if you did CS,1,B,4,0 and Port B pin 4 was already low, you could do an SM command to move the motor off of the sensor, as no falling edge would be generated as the axis comes off the sensor. You would only trip an EStop if the sensor went from a high to a low state.

oskay commented 8 years ago

I'm not quite understanding why there could be up to 8 active at once though - wouldn't it just be four? (one in each direction, for each of two motors)

It's potentially twice as complicated as that. Suppose that you have a mixed-axis geometry, e.g., Core-XY, H-Bot, T-Bot, etc. In a machine like this, a carriage is moved in the XY plane, by two motors, motor 1 and motor 2:

Now, suppose that there are four limit switches, which detect the carriage bumping into the X_Lo and X_Hi edges of motion, and the Y_Lo and Y_Hi edges of motion.

This leads to eight conditional limitations that we must put on the movement:

(1) If the X_Hi switch is tripped, we must then prevent Motor 1 from turning in the positive direction, since that would increase X. (2) If the X_Hi switch is tripped, we must then also prevent Motor 2 from turning in the positive direction, since that would increase X. (3) If the X_Lo switch is tripped, we must then prevent Motor 1 from turning in the negative direction, since that would decrease X. (4) If the X_Lo switch is tripped, we must then also prevent Motor 2 from turning in the negative direction, since that would decrease X.

(Cases 5-8 apply for the equivalent cases in the Y direction.)

What happens when one limit switch is tripped while both motors are moving? Do both motors stop?

I would say yes. Bumping into the limit switch would normally indicate that the range of acceptable movement has been exceeded, and any motion beyond that might be regarded as uncontrolled.

And just to be clear, we are thinking of looking for edges on the limit switches as the mechanism for triggering the EStop, correct? In other words, if you did CS,1,B,4,0 and Port B pin 4 was already low, you could do an SM command to move the motor off of the sensor, as no falling edge would be generated as the axis comes off the sensor. You would only trip an EStop if the sensor went from a high to a low state.

I would say that we would (1) want to yes detect edges in that way, but also (2) refuse to move in a direction that drives the carriage further into the limit switch. That is, detect the state of the switch, and only execute a received SM command if it moves off the switch or in a direction parallel to it. As I said above: "Once a given limit switch were tripped, it could prevent further motion in the direction indicated by edge. An SM command asking either motor to move in any direction forbidden would be ignored."

Added note: That is to say, since the CS command completely specifies the direction of motor movement (and which motor(s) are affected), we can confirm that the requested move is in the correct direction.

Arachnid commented 7 years ago

This would be really handy for making homing easier, too. I'd suggest a simpler alternative to the proposed solutions, though.

A command that lets you specify a GPIO pin and value to monitor. When any of the specified values are encountered, an e-stop is triggered, halting all motors (and possibly, emitting a message). The computer can then inspect the GPIOs to determine which stop was triggered, and take appropriate action (disable that estop, back off, etc).

This makes homing really simple, too: enable the appropriate limit, and tell the board to move a large amount in the desired direction, then wait until it triggers the endstop.

EmbeddedMan commented 7 years ago

I like this a lot. Simpler to implement, understand and use.

So something like "LE,,," (LE for Limit Enable), where is a letter port name, is the pin number on that port to monitor, and is 0 or 1.

The logic would go like this : Once the command is sent, after every step, the specified pin is checked to see if it is in . If it is, the move is aborted, and a message is sent back (say "LE trigger"). If you send more than one LE command, the last overwrite any previous ones. Once is seen, the command is no longer active. A command of "LE,0" will disable any outstanding LE trigger waiting to happen.

*Brian

On Mon, Feb 6, 2017 at 4:52 AM, Nick Johnson notifications@github.com wrote:

This would be really handy for making homing easier, too. I'd suggest a simpler alternative to the proposed solutions, though.

A command that lets you specify a GPIO pin and value to monitor. When any of the specified values are encountered, an e-stop is triggered, halting all motors (and possibly, emitting a message). The computer can then inspect the GPIOs to determine which stop was triggered, and take appropriate action (disable that estop, back off, etc).

This makes homing really simple, too: enable the appropriate limit, and tell the board to move a large amount in the desired direction, then wait until it triggers the endstop.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/evil-mad/EggBot/issues/58#issuecomment-277648348, or mute the thread https://github.com/notifications/unsubscribe-auth/AAbeCPvB1YtiMW2kUma6gnBRZzSVasGlks5rZvtzgaJpZM4Jx_at .

Arachnid commented 7 years ago

Yes, although I think being able to have multiple outstanding triggers would be an advantage for multiple limit switches. One way to do this would be to have it in the format LE,<port>,<mask>,<value>, and abort if read(port) & mask != value.

EmbeddedMan commented 7 years ago

Agreed - it would be wonderful to be able to turn on any number of pins to be a trigger. However, we may have a technical limitation. The ISR that steps the motors needs to run as fast and efficiently as possible. It it takes too long, then not only could we not have enough 'main line' CPU time for USB operation, but we could start missing steps if the ISR takes too long. Each added thing we have to check in that ISR makes it take longer, and I worry about having say 8 arbitrary pins to check. (That would mean creating a list of pins, then walking through the list after every step.)

I will prototype this up and see how much time it adds to check one pin, and see if adding multiple pins at the same time would easily be doable. It might work out just fine.

*Brian

On Mon, Feb 6, 2017 at 9:06 AM, Nick Johnson notifications@github.com wrote:

Yes, although I think being able to have multiple outstanding triggers would be an advantage for multiple limit switches. One way to do this would be to have it in the format LE,,,, and abort if port & mask != value.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/evil-mad/EggBot/issues/58#issuecomment-277709769, or mute the thread https://github.com/notifications/unsubscribe-auth/AAbeCHAsqGcM6iHBImjLBYDgTPYrGfV7ks5rZzb8gaJpZM4Jx_at .

Arachnid commented 7 years ago

If you can read a whole port - which the current API would seem to imply is doable - then the method I outlined should work, and requires no more computation than checking a single pin. It would impose the requirement that all endstops are on the same port, but I don't think that's untenable.

Thanks for offering to try it out!

EmbeddedMan commented 1 year ago

I now have an implementation of this feature. It's probably not perfect, and it's not exactly what was discussed above, but I think it's close enough to meet everyone's needs. Here's how it works:

On boot, the Limit Switch Check feature is disabled. So you have to explicitly turn it on in order for it to do anything.

Any time you want to turn it off, you just send CU,51,0

The Limit Switch Check feature looks at all of PortB. It will read their pin states, even if some or all of the pins are set to be outputs.

It has two primary settings, and they are both unsigned 8 bit values: LimitSwitchTarget and LimitSwitchMask.

If you set the LimitSwitchMask to a non-zero value, then every time through the motion ISR (25KHz) it will look at each bit in PortB (all at once). For any bit which is set in LimitSwitchMask, it will compare the corresponding bit from LimitSwitchTarget and the actual PortB pin value. If they match, then it will trigger the limit switch function (LimitSwitchTriggered is then true).

If the limit switch function gets triggered, any currently executing motion command is immediately terminated, and any pending motion commands in the FIFO are deleted. Also, no new stepper motor motion commands are permitted to enter the FIFO - they will be silently ignored. (I.e. you will still get back an "OK", but no motion will happen.) This behavior will exists until you disable the Limit Switch feature (by setting the LimitSwitchMask to 0). Setting LimitSwitchMask to 0 also clears LimitSwitchTriggered.

The command CU,51, sets the LimitSwitchMask value. The command CU,52, sets the LimitSwitchTarget value.

Bit 7 of the reply of the QG command is being changed to indicate the value of LimitSwitchTriggered. This allows you to poll to see if the limit switch function has triggered.

In addition, you can send CU,53,1 which will enable a new reply message from the EBB. Any time the limit switch feature is triggered, a Limit switch triggered. PortB=XX packet will be sent from the EBB to the PC. The XX value is the one byte hexadecimal value of PortB pins captured at the moment when the limit switch feature was triggered. You can use this new reply packet to get an asynchronous notification of the triggering of the limit switch function, and also receive the exact pin values of all of PortB at the moment it was triggered. Of course CU,53,0 turns off these notifications.

Any EM command will also clear the LimitSwitchTriggered value.

One use case for this feature is to enable one bit of PortB (say RB2) to be your limit switch. Normally this pin is high (it has a weak pull up enabled) and so the switch can simply connect between RB2 and GND. So you send CU,52,0 to say that you are looking for RB2 to go low, and then CU,51,4 to say that you only want to look at RB2. Then you might send a move command like SM,10000,10000,0 to move axis1 towards your limit switch. You could then poll with QG, looking for bit 7 to go high, which would indicate that the limit switch on RB2 has gone low. You would then need to send CU,51,0 in order to turn off the limit switch function and allow motion again.

Another use case might be to (say) set up four limit switches on the four high bits of PortB. Again, they all have weak pull ups, so your switches could simply connect to GND. You could then send CU,53,1 to turn on the limit switch reply packets, then CU,52,0 to say that you're looking for the pins to go low, and then CU,51,240 (240 decimal = 0xF0 hex) to say that you want to monitor bits 4-7 of PortB. Then you could do all of your plotting as normal. If something bad happened, and one of your move commands accidentally tripped one of the four limit switches, then you would get an immediate stoppage of all motion and a Limit switch triggered. PortB=XX message from the EBB where XX would indicate which limit switch(es) went low.

EmbeddedMan commented 1 year ago

Hopefully this is obvious, but if your motion stops because of a limit switch trigger, the EBB will not be in sync any longer with the PC with regards to motor positions. Whatever move was happening when the limit switch triggered was stopped somewhere in the middle. The global axis1 and axis2 position counters will still be accurate, of course, but the PC may think that the move was completed, when in fact it was only partially completed.

So after a limit switch stop, some type of homing process should occur to re-sync the actual position with where the PC thinks the motors are. Probably that was the whole intent of your move into the limit switch (i..e homing) but it's just something to keep in mind.

EmbeddedMan commented 1 year ago

This new feature will be part of the upcoming v3.0.0 release of EBB Firmware.

EmbeddedMan commented 4 months ago

This limit switch feature is now part of the official EBB firmware as of v3.0.2 merged into master as of PR #232 See ebb.html for complete documentation on how it works.