Closed chevellebro1 closed 8 years ago
You should be able to configure things so the Lidar Sensor triggers at the edge of the bed. You would want to configure Marlin for Min End stops and it should find the edge and call that 0.000 mm
The thing I am struggling with is there to configure this? I can't seem to find out how to trigger the endstop.
You will need something to interface between your LIDAR and Marlin, hardware wise I mean. Marlin only cares if the end switch is triggered or not, the"relay" device would need to check the distance threshold and trigger the pin.
Am I not able to manually change pinstate to act as if the endstop has been triggered? Right now I have the Lidar changing the pin associated with the endstop if the value is greater than the threshold. Do I need a relay in order to do this?
Electrically.... What does the Lidar put out? The easiest endstop interface to an AVR (and Marlin) is a switch that opens and closes. With the pull up resistors activated, you just need to connect this switch from a pin on the AVR and the other connection on the switch to electrical ground.
If your Lidar puts out a signal, you will need to turn that into something that Marlin thinks is a switch opening or closing.
The Lidar unit is attached: https://github.com/PulsedLight3D/LIDARLite_Basics/tree/master/Arduino/LIDARLite_PWM_GetDistance_ContinuousRead
The sensor counts how long the signal is HIGH and determines distance using that. I was hoping to use there distance reading to change the pin status and act as if the endstop was triggered
The example code uses pulseIn()
which is a blocking function, for this to be usable with Marlin we had to use an interrupt trigger. The best solution would you to adapt the example code:
digitalWrite()
pin X high.Oh! I get it! Your post is talking about using an AVR as the electronics to do the conversion. And then there would be a separate AVR that is running the Marlin firmware.
It looks like it puts out a Pulse Width Modulated signal. You can use an NE556 to watch for the width of the pulse and adjust it so it puts out a digital signal at the edge of the bed. If you did this, you would just connect this digital output to the pin you are trying to emulate a switch on.
I've tried adding the lidar function into the main loop but it slows down the process considerably. How can I have it gather more than one value without slowing down the machine?
Marlin's main loop ?
I created a lidar( ) function and put that into the void loop( ) but it seems to be slowing down the movements
Did you take time to read my comments ? I said pulseIn()
is a blocking function.
Sorry I misunderstood. So what would I use in place of pulseIn()
? I understand that I can trigger another pin to act as my HIGH but what would I replace the pulseIn
with?
Before going crazy test if the solution will fit your needs, I'm thinking it may not have enough resolution for the application.
Just do a test mockup: Do you have a spare Arduino ? Connect the LIDAR to the Arduino and load up the example sketch you linked in.
Adjust the sketch so when the distance you want to trigger the endstop is reached, it does digitalWrite()
to a pin, connect that pin to the Marlin endstop input.
This is the fastest way to test if it will work for you. Makes no sense at this stage to start messing with Marlin source code.
Arduino code to get you on the ballpark.
unsigned long pulse_width;
const unsigned int trigger = 100; // select here your trigger condition
const unsigned int endstop = 5; // Digital PIN connected to endstop
void setup()
{
Serial.begin(9600); // Start serial communications
pinMode(2, OUTPUT); // Set pin 2 as trigger pin
pinMode(3, INPUT); // Set pin 3 as monitor pin
digitalWrite(2, LOW); // Set trigger LOW for continuous read
pinMode(endstop , OUTPUT); // Set endstop pin as output
digitalWrite(endstop , LOW); // Set endstop LOW
}
void loop()
{
pulse_width = pulseIn(3, HIGH); // Count how long the pulse is high in microseconds
// Serial debug
if(pulse_width != 0){ // If we get a reading that isn't zero, let's print it
pulse_width = pulse_width/10; // 10usec = 1 cm of distance for LIDAR-Lite
Serial.println(pulse_width); // Print the distance
}
// endstop trigger
if (pulse_width <= trigger) digitalWrite(endstop, HIGH);
else digitalWrite(endstop, LOW);
delay(20); //Delay so we don't overload the serial port
}
Thank you, this works great! Now my next question is how to run this while the machine is moving? Since the pulseIn( ) is a block, how am I able to check without it stopping the machine?
As you're running this on a different hardware than Marlin is running on there are no issues with pulseIn()
nor with delay()
.
I see what you're saying, running a separate board for this function. I am a bit limited on space for electronics, is there an alternative for pulseIn( )?
You have to use interrupts, raising edge store the time stamp, falling edge do the diff from now and the stored time stamp and you have your distance.
All of this was said in my second reply to your question.
I'm sorry, I'm fairly new at all this. I appreciate you taking time to explain it to me
It's not that I do not want to help you but the change you want in Marlin is not as trivial as it seems. You should validate first in a practical way if the hardware solution of the LIDAR works for your intended use. The fastest way is to use an additional Arduino as a relay. The data sheet for that sensor shows the operating range up to 40m, in a CNC application we speak about fractions of a mm (unit).
For what I am doing, I want the edge finder to sense changes in height which are most likely going to be well within the accuracy of the sensor. For instance I usually mill foam which is 1". I want to use the Lidar to sense the change in height of 1" and trigger the endstop to mark the edge
Yes it's "in range", but the sensor was designed to operate up to 40m, 1" is 2.5cm. The example code they give specifies 10us as 1cm.. 10us is not even detectable by millis()
you have to use micros()
and micros()
is known for not be very accurate on AVR. And on top of this we do not know how wide the beam is..
Yes you are right, I will need to do more testing to see if it is plausible for what I want. I will get a second microprocessor to run the Lidar
Yes you are right, I will need to do more testing to see if it is plausible for what I want. I will get a second microprocessor to run the Lidar.
Just to prove the idea, a second AVR to run the Lidar is the right answer. But with a small NE556 chip (wired correctly) (and costing $.37) you can make the Lidar into a digital switch. If you are not manufacturing this, it doesn't matter. But if this is going to go a lot of places, you can dramatically cut costs if the idea proves out and works.
But with a small NE556 chip you can make the Lidar into a digital switch
This will be a couple of orders of magnitude easier do to than change Marlin to accept a LIDAR as a end-switch..
I almost have the sensor working now with the external board. I am having on(e) problem though with the homing code. I want the sensor to move and sense the edge of the material but instead of setting it to zero, I want it to store the value. I want the zero position to remain where it hits the endstops and this is a reference to those. I hope that makes sense. I've attached my code
static void lidar_homeaxis(int axis) {
#define HOMEAXIS_DO_LIDAR(LETTER) \
((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))
if (axis==X_AXIS ? HOMEAXIS_DO_LIDAR(X) :
axis==Y_AXIS ? HOMEAXIS_DO_LIDAR(Y) :
axis==Z_AXIS ? HOMEAXIS_DO_LIDAR(Z) :
0) {
int axis_home_dir = home_dir(axis) * -1;
current_position[axis] = 0;
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[axis] = 1.5 * max_length(axis) * axis_home_dir;
feedrate = 500;
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
current_position[axis] = 0;
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[axis] = -home_retract_mm(axis) * axis_home_dir;
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
destination[axis] = 2*home_retract_mm(X_AXIS) * axis_home_dir;
feedrate = 500;
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
axis_is_at_home(axis);
destination[axis] = current_position[axis];
feedrate = 0.0;
endstops_hit_on_purpose();
axis_known_position[axis] = true;
}
}
I want the sensor to move and sense the edge of the material but instead of setting it to zero, I want it to store the value. I want the zero position to remain where it hits the endstops and this is a reference to those. I hope that makes sense. I've attached my code
No, that doesn't make sense yet. Besides re-explaining what you want, can you answer "Why are you doing this?" That might give us a better idea what is needed.
For my cnc mill, I want a quick way to find the edge of a piece of material. Conventionally you would use an edge finder or a probe. I am hoping to replace this with the lidar sensor. I have had pretty good success so far. In the video attached, the machine zeros itself with the endstops before moving to a predefined position to start looking for the edge of the material. Once it finds the edge in the X direction, it then moves to the Y axis and also finds the edge there. This works great.
PROBLEM: Each times it finds the edge of the material, the machine position resets to 0,0,0. So when I find the edge of the material in the X axis, the machine zeroes itself and then moves to the Y axis where it repeats this and zeros on that edge. My issue is that because it is zeroing in both places, I am loosing my position for the edge of material in the X axis because it is reset when the Y finds the edge.
GOAL: I would like the machine to find the edge in the X axis and without resetting the machine zero, move to the Y axis and find the edge also without resetting zero. At this point I will have the edge position in X and Y. Then from here I want the machine to move to the corner of the two edges measured and then set machine zero.
Hopefully that helps explain more and the video will help.
Have you had a look at relative positioning ? You want to find you machine 0,0 and then the work piece 0,0 which will be relative to your machine 0,0 and should not replace it.
On a real CNC that's G54, on Marlin have a look at G92.
Please keep in your mind that the GCode used by a 3D printer may not be 100% valid for a CNC.
o_O
I'll see if I can adapt the G92 code for what I am doing. That's a good point, I don't want to move the home position, just reference it
I think relative positioning has a lot of merit here. But I've never used it so I'm kind of thinking about your problem from a different perspective. Isn't it appropriate for the CNC machine to position the corner of the material at (0,0) ? And you would just make sure your GCode has the generated part at the origin also?
But all that aside... Your code up above does not ask the Lidar sensor where it is. This code sets the current position (for the axis being homed) to 0.0 and goes towards the endstop until it bumps into the switch.
current_position[axis] = 0;
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[axis] = -home_retract_mm(axis) * axis_home_dir;
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
Then it retracts a little bit... And it should bump at a slower speed, but you have the 1st and 2nd bump happening at the same speed (which doesn't seem right).
destination[axis] = 2*home_retract_mm(X_AXIS) * axis_home_dir;
feedrate = 500;
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
And then this next code just sets the position based on the current location of the bump. But you never reference the Lidar sensor. (Unless you buried that way down into the stepper code that watches for endstops being triggered.)
axis_is_at_home(axis);
destination[axis] = current_position[axis];
feedrate = 0.0;
endstops_hit_on_purpose();
axis_known_position[axis] = true;
You are correct for the 0,0 position for a CNC machine. In the code software, you define the corner in which the material is homed and use that as the 0,0. The zero for the machine is constantly changing based on the program. The homing endstops are just used to reference and not as a zero as it is with 3D printing.
I should have included this additional code:
case 20: // G20 Lidar Edge Finder
saved_feedrate = feedrate;
saved_feedmultiply = feedmultiply;
feedmultiply = 100;
previous_millis_cmd = millis();
// First Move X and Y to Home Position
home_all_axis = !((code_seen(axis_codes[X_AXIS])) || (code_seen(axis_codes[Y_AXIS])) || (code_seen(axis_codes[Z_AXIS])));
if((home_all_axis) || (code_seen(axis_codes[X_AXIS])))
{
HOMEAXIS(X);
}
if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
HOMEAXIS(Y);
}
if(code_seen(axis_codes[X_AXIS]))
{
if(code_value_long() != 0) {
current_position[X_AXIS]=code_value()+add_homing[X_AXIS];
}
}
if(code_seen(axis_codes[Y_AXIS])) {
if(code_value_long() != 0) {
#ifdef SCARA
current_position[Y_AXIS]=code_value();
#else
current_position[Y_AXIS]=code_value()+add_homing[Y_AXIS];
#endif
}
}
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
//Enable Lidar Endstop and Zero to Edge of Material
destination_lidar[X_AXIS] = 60; //Position to Start Lidar Edgefinder
destination_lidar[Y_AXIS] = 20;
feedrate_lidar = 2000;
plan_buffer_line(destination_lidar[X_AXIS], destination_lidar[Y_AXIS], destination_lidar[Z_AXIS], destination_lidar[E_AXIS], feedrate_lidar/60, active_extruder);
st_synchronize();
enable_endstops(true);
feedrate = 0.0;
for(int8_t i=0; i < NUM_AXIS; i++) {
destination[i] = current_position[i];
}
home_all_axis = !((code_seen(axis_codes[X_AXIS])) || (code_seen(axis_codes[Y_AXIS])) || (code_seen(axis_codes[Z_AXIS])));
if((home_all_axis) || (code_seen(axis_codes[X_AXIS])))
{
digitalWrite(LIDAR_RESET, HIGH); //Trigger external AVR board to reset saved distance
delay(1000);
digitalWrite(LIDAR_RESET, LOW);
digitalWrite(LIDAR_TRIGGER, HIGH); //Trigger external AVR to enable endstop
delay(500);
LIDAR_HOMEAXIS(X);
digitalWrite(LIDAR_TRIGGER, LOW);
}
delay(1000);
destination_lidar[X_AXIS] = 80;
destination_lidar[Y_AXIS] = 245;
feedrate_lidar = 2000;
plan_buffer_line(destination_lidar[X_AXIS], destination_lidar[Y_AXIS], destination_lidar[Z_AXIS], destination_lidar[E_AXIS], feedrate_lidar/60, active_extruder);
st_synchronize();
if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
digitalWrite(LIDAR_RESET, HIGH);
delay(1000);
digitalWrite(LIDAR_RESET, LOW);
digitalWrite(LIDAR_TRIGGER, HIGH);
delay(500);
LIDAR_HOMEAXIS(Y);
digitalWrite(LIDAR_TRIGGER, LOW);
}
delay(1000);
And this is the code being run on the external AVR that controls the lidar sensor
unsigned long pulse_width;
int trigger_pin = 2;
int monitor_pin = 3;
int reset_pin = 4;
int endstop = 10; // Digital PIN connected to endstop
int lidar_pin = 5;
unsigned int time = 0;
unsigned int lidar = 0;
unsigned int bed_height = 0;
unsigned int reset = 0;
unsigned int trigger = 0; // select here your trigger condition
void setup()
{
Serial.begin(9600); // Start serial communications
pinMode(trigger_pin, OUTPUT); // Set pin 2 as trigger pin
pinMode(monitor_pin, INPUT); // Set pin 3 as monitor pin
pinMode(reset_pin, INPUT_PULLUP); //Input from main board
pinMode(lidar_pin, INPUT_PULLUP); //
digitalWrite(trigger_pin, LOW); // Set trigger LOW for continuous read
pinMode(endstop , OUTPUT); // Set endstop pin as output
digitalWrite(endstop , LOW); // Set endstop LOW
}
void loop()
{
lidar = digitalRead(lidar_pin);
reset = digitalRead(reset_pin);
pulse_width = pulseIn(monitor_pin, HIGH); // Count how long the pulse is high in microseconds
// Serial debug
if(pulse_width != 0){ // If we get a reading that isn't zero, let's print it
pulse_width = pulse_width/10; // 10usec = 1 cm of distance for LIDAR-Lit
Serial.print("DISTANCE ");
Serial.println(pulse_width); // Print the distance
}
//Reset Bed Position
if (reset == 1) {
bed_height = pulse_width;
trigger = bed_height - 5;
Serial.println("RESET");
}
else {
}
// endstop trigger
if (lidar == 1) {
if (pulse_width <= trigger) {
digitalWrite(endstop, HIGH);
Serial.println("TRIGGERED!!");
}
else {
digitalWrite(endstop, LOW);
}
}
else {
digitalWrite(endstop, LOW);
}
//Serial Debugger
Serial.print("BED HEIGHT ");
Serial.println(bed_height);
Serial.print("TRIGGER ");
Serial.println(trigger);
Serial.print("STAGE");
Serial.println(lidar);
Serial.print("RESET");
Serial.println(reset);
Serial.println();
delay(0); //Delay so we don't overload the serial port
}
I stil want the machine 0,0 to be set at the corner. I just want to delay the setting zero until after both the X and Y edges have been found and the machine is then moved to the corner. Then set machine 0,0 on the corner of the material.
Relative positioning is specially important on a CNC because you'll never want to cut your table, so after homing XYZ and zeroing your workpiece XYZ then you can only go as deep as the workpiece Z height and never into the table. CNC uses negative Z as we're removing material from the workpiece.
Thank you for your interest making Marlin better and reporting this issue but this topic has been open for a long period of time without any further development. Marlin has been under heavy development for the past couple of months and moving to it's last mile to finish the RC cycle and release Marlin v1.1.0. We suggest you to try out the latest RCBugfix branch and reopening this issue if required.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
I would like to use a Lidar sensor as an edge finder for a CNC mill. Is it possible to set the Lidar to trigger the endstop pin if the distance changes so that the machine ZERO is at the edge of the material?