Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FR] Polar kinematics for vertical CNC or plotter #5275

Closed
tilkor opened this issue Nov 21, 2016 · 17 comments
Closed

[FR] Polar kinematics for vertical CNC or plotter #5275

tilkor opened this issue Nov 21, 2016 · 17 comments
Labels
C: Motion T: Feature Request Features requested by users.

Comments

@tilkor
Copy link

tilkor commented Nov 21, 2016

Hello,

I came across an open source palorgraph/Vertical plotter style CNC mill/router (http://www.maslowcnc.com/home/) that I thought would be a nice feature to add to marlin. This style of CNC looks like it would be very easy to DIY build using a Ramps 1.4 board.

I found Rick McConny's Pen Plotter based off Marlin (https://github.com/RickMcConney/PenPlotter/tree/master/Marlin) that is the same concept just with the Z axis limited.

I am not a coder by any means so I really do not have a clue how hard it would be to add this feature in but I would greatly appreciate it if it was taken into consideration.

Thanks,

-Maslowcnc souce code (https://github.com/MaslowCNC/Firmware/tree/master/cnc_ctrl_v1)

@tilkor tilkor changed the title Polar for V-Plotter CNC Mill Add-on Polar for POLARGRAPH_CNC Add-on Nov 28, 2016
@tilkor
Copy link
Author

tilkor commented Nov 28, 2016

I have based the code off McConny's work.

Configuration.h:

// Uncomment the following line to enable POLARGRAPH_CNC kinematics
#define POLARGRAPH_CNC

Marlin.h:

#ifdef POLARGRAPH_CNC
  extern float polarGRAPH_CNC_HomeY;
  extern float polarGRAPH_CNC_HomeZ;
  extern float polarGRAPH_CNC_PageWidth;
  extern float polarGRAPH_CNC_LastA;
  extern float polarGRAPH_CNC_LastB;
  extern float polarGRAPH_CNC_LastC;
#endif

Planner.cpp:

#ifdef POLARGRAPH_CNC

	float aPos = sqrt(x*x + y*y);
	float bPos = sqrt(sq(POLARGRAPH_CNC_PageWidth - x) + y*y);
	float cPos = z
	/*
	SERIAL_PROTOCOLPGM("X:");
	SERIAL_PROTOCOL(x);
	SERIAL_PROTOCOLPGM(" Y:");
	SERIAL_PROTOCOL(y);
	SERIAL_PROTOCOLPGM(" Z:");
	SERIAL_PROTOCOL(z);

	SERIAL_PROTOCOLPGM(" A:");
	SERIAL_PROTOCOL(aPos);
	SERIAL_PROTOCOLPGM(" B:");
	SERIAL_PROTOCOL(bPos);
	SERIAL_PROTOCOLPGM(" C:");
	SERIAL_PROTOCOL(cPos);

	SERIAL_PROTOCOLPGM(" LA:");
	SERIAL_PROTOCOL(POLARGRAPH_CNC_LastA);
	SERIAL_PROTOCOLPGM(" LB:");
	SERIAL_PROTOCOL(POLARGRAPH_CNC_LastB);
	SERIAL_PROTOCOLPGM(" LC:");
	SERIAL_PROTOCOL(POLARGRAPH_CNC_LastC);
	*/

	target[X_AXIS] = lround((aPos - POLARGRAPH_CNC_LastA)*axis_steps_per_unit[X_AXIS]);
	target[Y_AXIS] = lround((bPos - POLARGRAPH_CNC_LastB)*axis_steps_per_unit[Y_AXIS]);
	target[Z_AXIS] = lround((cPos - POLARGRAPH_CNC_LastC)*axis_steps_per_unit[Z_AXIS]);
	position[X_AXIS] = 0;
	position[Y_AXIS] = 0;
	position[Z_AXIS] = 0;
	POLARGRAPH_CNC_LastA = aPos;
	POLARGRAPH_CNC_LastB = bPos;
	POLARGRAPH_CNC_LastC = cPos;
	/*
	SERIAL_PROTOCOLPGM(" TX:");
	SERIAL_PROTOCOL(target[X_AXIS]);
	SERIAL_PROTOCOLPGM(" TY:");
	SERIAL_PROTOCOL(target[Y_AXIS]);
	SERIAL_PROTOCOLPGM(" TZ:");
	SERIAL_PROTOCOL(target[Z_AXIS]);
	SERIAL_PROTOCOL("\n");
	*/

#endif

Marlin_main.cpp:

#ifdef POLARGRAPH_CNC
float POLARGRAPH_CNC_HomeY = 250;
float POLARGRAPH_CNC_HomeZ = 0;
float POLARGRAPH_CNC_PageWidth = 840;
float POLARGRAPH_CNC_LastA;
float POLARGRAPH_CNC_LastB;
float POLARGRAPH_CNC_LastC;

void POLARGRAPH_CNC_Home(float homeY, float homeZ) {
	POLARGRAPH_CNC_HomeY = homeY;
	POLARGRAPH_CNC_HomeZ = homeZ;
	float x = POLARGRAPH_CNC_PageWidth / 2;
	float y = POLARGRAPH_CNC_HomeY;
	float z = POLARGRAPH_CNC_HomeZ;
	current_position[X_AXIS] = x;
	current_position[Y_AXIS] = y;
	current_position[Z_AXIS] = z;

	float aPos = sqrt(x*x + y*y);
	float bPos = sqrt(sq(POLARGRAPH_CNC_PageWidth - x) + y*y);
	float cPos = z
	long a = lround(aPos*axis_steps_per_unit[X_AXIS]);
	long b = lround(bPos*axis_steps_per_unit[Y_AXIS]);
	long c = lround(cPos*axis_steps_per_unit[Z_AXIS]);

	st_set_position(a, b, c, 0);
	POLARGRAPH_CNC_LastA = aPos;
	POLARGRAPH_CNC_LastB = bPos;
	POLARGRAPH_CNC_LastC = cPos;
}

void POLARGRAPH_CNC_Width(float value) {
	POLARGRAPH_CNC_PageWidth = value;
	POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeY);
	POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeZ);
}

void POLARGRAPH_CNC_SegmentLine(float x2, float y2, float z2) {
	float x1 = current_position[X_AXIS];
	float y1 = current_position[Y_AXIS];
	float z1 = current_position[Z_AXIS];
	float dx = x2 - x1;
	float dy = y2 - y1;
	float dz = z2 - z1;
	float x = x1;
	float y = y1;
	float z = z1;
	float steps = fabs(dx);
	if (fabs(dy) > steps)
		steps = fabs(dy);
	dx = dx / steps;
	dy = dy / steps;
	dz = dz / steps;
	// Com::print("seg line ");
	// Com::print((int)steps);
	// Com::print("\n ");
	for (int s = 0; s<steps - 1; s++) {
		x += dx;
		y += dy;
		z += dz;
		destination[X_AXIS] = x;
		destination[Y_AXIS] = y;
		destination[Z_AXIS] = z;
		prepare_move();
	}
	destination[X_AXIS] = x2;
	destination[Y_AXIS] = y2;
	destination[Z_AXIS] = z2;
	prepare_move();
}
#endif

#ifdef POLARGRAPH_CNC
  polarGRAPH_CNC_Home(250);
#endif

#ifdef POLARGRAPH_CNC
			polarGRAPH_CNC_SegmentLine(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
		#else
			prepare_move();
		#endif

#ifdef POLARGRAPH_CNC
   case 1: {
	   if (code_seen('Y')) {
		   POLARGRAPH_CNC_Home(code_value());
	   }
   }
   case 4: {
	   if (code_seen('X')) {
		   POLARGRAPH_CNC_Width(code_value());
	   }
   }
#endif

#ifdef POLARGRAPH_CNC

  plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply / 60 / 100.0, active_extruder);

#endif

#if ! (defined DELTA || defined SCARA || defined POLAR || defined POLARGRAPH_CNC)
  // Do not use feedmultiply for E or Z only moves
  if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
      plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
  }
  else {
    plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
  }
#endif // !(DELTA || SCARA || POLARGRAPH_CNC)

@thinkyhead
Copy link
Member

thinkyhead commented Dec 2, 2016

@tilkor Some context seems to be missing in the last set of code for Marlin_main.cpp. Where is the code following the POLARGRAPH_CNC_SegmentLine function meant to go? Where is the code for Planner.cpp meant to go?

Also, is the case 1 supposed to fall through into case 4, or is a break statement needed?

@thinkyhead
Copy link
Member

thinkyhead commented Dec 2, 2016

Here is the code as it would need to be updated, style-wise, for the latest Marlin codebase:

Configuration.h:

// Uncomment the following line to enable POLARGRAPH_CNC kinematics
#define POLARGRAPH_CNC

Conditionals_post.h:

#define IS_KINEMATIC (ENABLED(DELTA) || IS_SCARA || ENABLED(POLAR) || ENABLED(POLARGRAPH_CNC))

Marlin.h:

#if ENABLED(POLARGRAPH_CNC)
  extern float polarGRAPH_CNC_PageWidth,
               polarGRAPH_CNC_LastA,
               polarGRAPH_CNC_LastB,
               polarGRAPH_CNC_LastC;
#endif

Planner.cpp:

#if ENABLED(POLARGRAPH_CNC)

  const float aPos = HYPOT(x, y),
              bPos = HYPOT(POLARGRAPH_CNC_PageWidth - x, y),
              cPos = z;
  /*
  SERIAL_PROTOCOLPGM("X:");
  SERIAL_PROTOCOL(x);
  SERIAL_PROTOCOLPGM(" Y:");
  SERIAL_PROTOCOL(y);
  SERIAL_PROTOCOLPGM(" Z:");
  SERIAL_PROTOCOL(z);

  SERIAL_PROTOCOLPGM(" A:");
  SERIAL_PROTOCOL(aPos);
  SERIAL_PROTOCOLPGM(" B:");
  SERIAL_PROTOCOL(bPos);
  SERIAL_PROTOCOLPGM(" C:");
  SERIAL_PROTOCOL(cPos);

  SERIAL_PROTOCOLPGM(" LA:");
  SERIAL_PROTOCOL(POLARGRAPH_CNC_LastA);
  SERIAL_PROTOCOLPGM(" LB:");
  SERIAL_PROTOCOL(POLARGRAPH_CNC_LastB);
  SERIAL_PROTOCOLPGM(" LC:");
  SERIAL_PROTOCOL(POLARGRAPH_CNC_LastC);
  */

  target[X_AXIS] = lround((aPos - POLARGRAPH_CNC_LastA) * axis_steps_per_unit[X_AXIS]);
  target[Y_AXIS] = lround((bPos - POLARGRAPH_CNC_LastB) * axis_steps_per_unit[Y_AXIS]);
  target[Z_AXIS] = lround((cPos - POLARGRAPH_CNC_LastC) * axis_steps_per_unit[Z_AXIS]);
  position[X_AXIS] = position[Y_AXIS] = position[Z_AXIS] = 0;
  POLARGRAPH_CNC_LastA = aPos;
  POLARGRAPH_CNC_LastB = bPos;
  POLARGRAPH_CNC_LastC = cPos;
  /*
  SERIAL_PROTOCOLPGM(" TX:");
  SERIAL_PROTOCOL(target[X_AXIS]);
  SERIAL_PROTOCOLPGM(" TY:");
  SERIAL_PROTOCOL(target[Y_AXIS]);
  SERIAL_PROTOCOLPGM(" TZ:");
  SERIAL_PROTOCOL(target[Z_AXIS]);
  SERIAL_PROTOCOL("\n");
  */

#endif

Marlin_main.cpp:

#if ENABLED(POLARGRAPH_CNC)
  float POLARGRAPH_CNC_HomeY = 250,
        POLARGRAPH_CNC_HomeZ = 0,
        POLARGRAPH_CNC_PageWidth = 840,
        POLARGRAPH_CNC_LastA,
        POLARGRAPH_CNC_LastB,
        POLARGRAPH_CNC_LastC;

  void POLARGRAPH_CNC_Home(const float &homeY, const float &homeZ) {
    POLARGRAPH_CNC_HomeY = homeY;
    POLARGRAPH_CNC_HomeZ = homeZ;
    const float x = POLARGRAPH_CNC_PageWidth * 0.5,
                y = POLARGRAPH_CNC_HomeY,
                z = POLARGRAPH_CNC_HomeZ;
    current_position[X_AXIS] = x;
    current_position[Y_AXIS] = y;
    current_position[Z_AXIS] = z;

    float aPos = HYPOT(x, y),
          bPos = HYPOT(POLARGRAPH_CNC_PageWidth - x, y),
          cPos = z;
    long a = lround(aPos * axis_steps_per_unit[X_AXIS]),
         b = lround(bPos * axis_steps_per_unit[Y_AXIS]),
         c = lround(cPos * axis_steps_per_unit[Z_AXIS]);

    stepper.set_position(a, b, c, 0);
    POLARGRAPH_CNC_LastA = aPos;
    POLARGRAPH_CNC_LastB = bPos;
    POLARGRAPH_CNC_LastC = cPos;
  }

  void POLARGRAPH_CNC_Width(const float &value) {
    POLARGRAPH_CNC_PageWidth = value;
    POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeY);
    POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeZ);
  }

  void POLARGRAPH_CNC_SegmentLine(const float &x2, const float &y2, const float &z2) {
    const float x1 = current_position[X_AXIS],
                y1 = current_position[Y_AXIS],
                z1 = current_position[Z_AXIS];
    float dx = x2 - x1, dy = y2 - y1, dz = z2 - z1, x = x1, y = y1, z = z1;
    const float steps = fabs(dx);
    NOLESS(steps, fabs(dy));
    dx /= steps;
    dy /= steps;
    dz /= steps;
    // Com::print("seg line ");
    // Com::print((int)steps);
    // Com::print("\n ");
    for (int s = 0; s < steps - 1; s++) {
      x += dx;
      y += dy;
      z += dz;
      destination[X_AXIS] = x;
      destination[Y_AXIS] = y;
      destination[Z_AXIS] = z;
      prepare_move_to_destination();
    }
    destination[X_AXIS] = x2;
    destination[Y_AXIS] = y2;
    destination[Z_AXIS] = z2;
    prepare_move_to_destination();
  }

#endif // POLARGRAPH_CNC

#if ENABLED(POLARGRAPH_CNC)
  polarGRAPH_CNC_Home(250);
#endif

#if ENABLED(POLARGRAPH_CNC)
  polarGRAPH_CNC_SegmentLine(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
#else
  prepare_move_to_destination();
#endif

#if ENABLED(POLARGRAPH_CNC)
  case 1: { if (code_seen('Y')) POLARGRAPH_CNC_Home(code_value()); }
  case 4: { if (code_seen('X')) POLARGRAPH_CNC_Width(code_value()); }
#endif

#if ENABLED(POLARGRAPH_CNC)

  planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], MMS_SCALED(feedrate), active_extruder);

#endif

#if !IS_KINEMATIC
  // Do not use feedmultiply for E or Z only moves
  if (current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS])
    planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], MMM_TO_MMS(feedrate), active_extruder);
  else
    planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], MMS_SCALED(feedrate), active_extruder);
#endif // !(DELTA || SCARA || POLARGRAPH_CNC)

@tilkor
Copy link
Author

tilkor commented Dec 2, 2016

I hope this helps.

Planner.cpp code goes under, float junction_deviation = 0.1; I have it starting at line 563.

Marlin_main.cpp code

Routines, starting at line 440

#ifdef POLARGRAPH_CNC
float POLARGRAPH_CNC_HomeY = 250;
float POLARGRAPH_CNC_HomeZ = 0;
float POLARGRAPH_CNC_PageWidth = 840;
float POLARGRAPH_CNC_LastA;
float POLARGRAPH_CNC_LastB;
float POLARGRAPH_CNC_LastC;
.............
destination[Z_AXIS] = z2;
	prepare_move();
}
#endif

Under void process_commands()

void process_commands()
{
  unsigned long codenum; //throw away variable
  char *starpos = NULL;
#ifdef ENABLE_AUTO_BED_LEVELING
  float x_tmp, y_tmp, z_tmp, real_z;
#endif
  if(code_seen('G'))
  {
    switch((int)code_value())
    {
    case 0: // G0 
          if(Stopped == false) {
        get_coordinates(); // For X Y Z E F
          #ifdef FWRETRACT
            if(autoretract_enabled)
            if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
              float echange=destination[E_AXIS]-current_position[E_AXIS];
              if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to retract or recover
                  current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations
                  plan_set_e_position(current_position[E_AXIS]); //AND from the planner
                  retract(!retracted);
                  return;
              }
            }
          #endif //FWRETRACT

           prepare_move();
 
        
        //ClearToSend();
      }
      break;
    case 1: // G1
      if(Stopped == false) {
        get_coordinates(); // For X Y Z E F
          #ifdef FWRETRACT
            if(autoretract_enabled)
            if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
              float echange=destination[E_AXIS]-current_position[E_AXIS];
              if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to retract or recover
                  current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations
                  plan_set_e_position(current_position[E_AXIS]); //AND from the planner
                  retract(!retracted);
                  return;
              }
            }
          #endif //FWRETRACT
      
				#ifdef POLARGRAPH_CNC
			polarGRAPH_CNC_SegmentLine(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
		#else
			prepare_move();
		#endif

        //ClearToSend();
      }
      break;
#ifndef SCARA //disable arc support

@thinkyhead thinkyhead added the T: Question Questions, generally redirected to other groups. label Dec 3, 2016
@thinkyhead
Copy link
Member

@tilkor Thanks. I hope some will find this useful. It would be interesting to see polar kinematics integrated into the latest code-base, but obviously that is more involved than merely the handful of changes laid out here. I've recently been working on a SCARA robot for a client, and a myriad of changes were required to support those specific kinematics throughout the code-base. I would be interested to see a video and other details about the specific machine that you are trying to support.

@tilkor
Copy link
Author

tilkor commented Dec 3, 2016

I greatly appreciate your help in cleaning up the code, I am still working out all the details but this is kind of the design i had in mind.

The main goal is to make it compact so when not in use it would folds up neatly against a wall with hinges along the top and a folding standoff at the bottom. The idea is to be able to cut out CAD designs from a sheet of plywood/steel using a router/plasma cutter attached to bike chains with counter weights through a step motors attached to the red squares.

I want run it all a arduino/ramps setup (super cheap) with 3 nema-17 (two mounted on the back side of the red plates). I would use the Z-axis 3rd nema to control the router's cut depth as it takes passes over the design.

polargraph_cnc build 1

polargraph_cnc build 2

@Cromaglious
Copy link

There is some interest in using polar with a linear actuator to be used as a portable plasma cutter. On youtube with user AvE. https://www.youtube.com/watch?v=IllVwt6CRJQ

@tilkor
Copy link
Author

tilkor commented Mar 8, 2017

I like the idea, I have not had time to work on this project recently.

I have based this mostly on a pen plotter and knowing the distance between the two motors (page width).

@fiveangle
Copy link
Contributor

fiveangle commented Jun 26, 2017

I was looking for info on MaslowCNC and a google search brought me here - lol

Basically same idea as PenPlotter here, but a 4x8 plywood CNC router.

https://www.youtube.com/watch?v=CIQC5ZyzfDM
https://www.youtube.com/watch?v=Q-KCZoxvzcQ

Looks like it runs it's own home-rolled FW:

https://github.com/MaslowCNC/Firmware

Unfortunately, because it uses DC motors with ~8k steps/rotation rotory encoders, it doesn't look like it would be a slam-dunk for porting to Marlin, even if polar kinematics were implemented unless you slap an Arduino running Misan's stepper->servo closed-loop converter software between: https://github.com/misan/dcservo

Come to think of it, once 32-bit Marlin becomes commonplace, I could see Marlin actually handling the closed-loop DC servo translation directly. This would be so awesome for CNC. One can dream... :)

@boelle
Copy link
Contributor

boelle commented Feb 18, 2019

@tilkor

Please post your question either on discord: https://discord.gg/n5NJ59y or on facebook: https://www.facebook.com/groups/2080308602206119/
The issue list is for bugs and feature requests only
Please close this issue once you have posted it on one of the 2 links
Thanks :-D

@boelle
Copy link
Contributor

boelle commented Mar 12, 2019

@thinkyhead i think we can close this one

again its labeled as a question and there is no activity from the OP

@boelle
Copy link
Contributor

boelle commented Jun 22, 2019

yep we should be able to close this one, no activity for months

@fiveangle
Copy link
Contributor

The issue list is for bugs and feature requests only

This was a feature request for implementing the polar kinematics. Whoever put the question tag on it probably just skimmed it quickly.

@phantomse
Copy link

In my search for an hanging all in one V-Plotter. I wanted to make it wireless (Battery or Power-line only, or get its power from the two cables it hangs from), much easier to set up and calibrate no matter of the size of the surface.

ESP3D continues figuring out the wireless part and can be added as library in Marlin. Luc is maintaining a version of Marlin 2.0 with ESP3D integrated.

There is a project which has all steps needed to change in Marlin (old version) for an V-Plotter https://github.com/RickMcConney/PenPlotter
Only since Marlin 2.0 there is support for esp32 so there may be some changes.

Hardware:
UNO D1 R32 (only one pin seams to be incompatible, snippet it off) + CNC Shield V3.0
LCD + Stepper + Servo + Solenoid + Endstops + SDCard ... => auto color changing and advanced functions
all in one, similar to https://hackster.imgix.net/uploads/attachments/536161/img_0131_joZbk8YliZ.JPG?auto=compress%2Cformat&w=1280&h=960&fit=max

@thinkyhead
Copy link
Member

I've been preferring Makelangelo for hanging plotter firmware. Marlin won't be integrating plotter or additional CNC or Laser support before version 2.1, but we definitely encourage others to adapt Marlin to special hardware.

@thinkyhead thinkyhead added T: Feature Request Features requested by users. and removed T: Question Questions, generally redirected to other groups. labels Jul 3, 2019
@thinkyhead thinkyhead added this to the 2.1 milestone Jul 3, 2019
@thinkyhead thinkyhead changed the title Polar for POLARGRAPH_CNC Add-on [FR] Polar kinematics for vertical CNC or plotter Jul 3, 2019
@boelle boelle removed this from the 2.1 milestone Jan 19, 2020
@thisiskeithb
Copy link
Member

Added in #22790

@github-actions
Copy link

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.

@github-actions github-actions bot locked and limited conversation to collaborators Mar 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
C: Motion T: Feature Request Features requested by users.
Projects
None yet
Development

No branches or pull requests

7 participants