APIs, concepts, guides, and more
GcodeMotion.cs
1
33using RSI.RapidCode.dotNET; // Import our RapidCode Library.
34using NUnit.Framework;
35using System;
36using System.Linq;
37using System.Threading;
38using System.IO;
39using System.Runtime.InteropServices;
40
41#if DOXYGEN // RSI internal documentation use only
42using RSI.RapidCode;
44#endif
45
48{
49 public override void Execute(GcodeCallbackData data)
50 {
51 Console.WriteLine("G-Code Callback executed: " + data.LineNumber + " " + data.LineText);
52
53 // if you want to nofity the Gcode object that there's an error processing, set its error details:
54 // data.UserError.number = RSIErrorMessage.RSI_ERROR_MESSAGE_DYNAMIC;
55 // data.UserError.text = "This is an error from the callback.";
56 }
57}
58
59[TestFixture]
60[Category("Software")]
61public class GcodeMotion : SampleAppTestBase
62{
63 [SetUp]
64 public void Setup()
65 {
66 jointsMultiAxis?.AxisRemoveAll();
67 }
68
69 [TearDown]
70 public void Teardown()
71 {
72 robot?.EStop();
73 robot?.MotionDoneWait();
74 robot?.ClearFaults();
75 Robot.RobotDelete(controller, robot);
76 robot = null;
77
78 jointsMultiAxis?.Abort();
79 Thread.Sleep(50);
80 jointsMultiAxis?.ClearFaults();
81 }
82
83 private void VerifyModel(KinematicModel model, string expectedName, LinearUnits expectedUnits = LinearUnits.None)
84 {
85 var actualUnits = model.UnitsGet();
86 Assert.That(actualUnits, Is.EqualTo(expectedUnits), $"Expected model units to be '{expectedUnits}' but was '{actualUnits}' instead!");
87 var actualName = model.NameGet();
88 Assert.That(actualName, Is.EqualTo(expectedName), $"Expected model name to be '{expectedName}' but was '{actualName}' instead!");
89 }
90
91 [Test]
92 public void GcodeBasic()
93 {
96 string gcodeProgram = "G91; Sets the programming mode to RELATIVE\n" +
97 "G64; Turns off exact stop mode(Default)\n" +
98 "G1 X1.0 Y0.0 Z0.0 A1.0 F60.0; Move on USERUNIT in positive x direction at 60in/min. Moves Free axis A to position 1.0.\n" +
99 "G3 X1 Y1 I0 J1; Counter clockwise arc with a center point of 0,1,0 and end point of 1,1,0 relative to the current position\n" +
100 "M80; Show how to use an M-code with GcodeCallback!\n";
101
102 // We assume the axes have been confgured and homed properly prior this this program.
103 const string xLabel = "X-Axis";
104 const string yLabel = "Y-Axis";
105 const string zLabel = "Z-Axis";
106 const string aLabel = "A-Axis";
107
108 x_axis.UserLabelSet(xLabel);
109 y_axis.UserLabelSet(yLabel);
110 z_axis.UserLabelSet(zLabel);
111 a_axis.UserLabelSet(aLabel);
112
113 // The joint index of each axis is the index within the MultiAxis object.
114 // "X-Axis" has joint index 0
115 // "Y-Axis" has joint index 1
116 // "Z-Axis" has joint index 2
117 // "A-Axis" has joint index 3
118 Axis[] axes = new Axis[] { x_axis, y_axis, z_axis, a_axis };
119 jointsMultiAxis.AxesAdd(axes, axes.Length);
120 jointsMultiAxis.ClearFaults();
121 jointsMultiAxis.AmpEnableSet(true);
122
123 const string modelName = "RSI_XYZA";
124 const double scaling = 1.0, offset = 0.0;
125 LinearModelBuilder builder = new LinearModelBuilder(modelName);
126 builder.JointAdd(new LinearJointMapping(0, CartesianAxis.X) { ExpectedLabel = xLabel, Scaling = scaling, Offset = offset });
127 builder.JointAdd(new LinearJointMapping(1, CartesianAxis.Y) { ExpectedLabel = yLabel, Scaling = scaling, Offset = offset });
128 builder.JointAdd(new LinearJointMapping(2, CartesianAxis.Z) { ExpectedLabel = zLabel, Scaling = scaling, Offset = offset });
129 builder.FreeAxisAdd(new ModelAxisMapping(3) { ExpectedLabel = aLabel, Scaling = scaling, Offset = offset }); // Add a free axis.
130
131 // Create a Robot object with a multi axis containing all joints and the kinematic type
132 robot = Robot.RobotCreate(controller, jointsMultiAxis, builder, MotionController.AxisFrameBufferSizeDefault);
134
135 robot.Gcode.AccelerationRateSet(1000); // UserUnits per minute squared
136
137 // The free axis index here refers to the index in the RobotPosition freeAxes array. We use index 0 here to refer to the first position in that array.
138 robot.Gcode.FreeAxisLetterSet('A', 0);
139
141 robot.Gcode.CallbackRegister(callback); // Register a callback to be called when the Gcode encounters any M-code command
142
143 try
144 {
145 robot.Gcode.Load(gcodeProgram); // Loads in the string and prepairs it for execution
146 }
147 catch (Exception e)
148 {
149 Console.WriteLine("Error loading G-Code: " + e.Message);
150
151 // get any additional G-Code errors (will give you details of every line number that has an error in parsing or processing)
153 throw e; // exit the program
154 }
155 // print some details about the upcoming motion
156 Console.WriteLine("G-Code Line Count: " + robot.Gcode.LineCountGet());
157 Console.WriteLine("G-Code Error Log Count: " + robot.Gcode.ErrorLogCountGet());
158 Console.WriteLine("G-code estimated run time: " + robot.Gcode.DurationGet() + " seconds");
159
160 robot.Gcode.Run(); // Starts the motion. Calling with the false arguement for non blocking behavior
161 Int64 activeLineNumber = 0;
162 do
163 {
164 Thread.Sleep(200);
165 if (activeLineNumber != robot.Gcode.ExecutingLineNumberGet()) // only write if we are on a new line
166 {
167 activeLineNumber = robot.Gcode.ExecutingLineNumberGet();
168 Console.WriteLine("G-Code Line Number: " + activeLineNumber);
169 }
170 } while (robot.Gcode.IsRunning());
171
172 HelperFunctions.CheckErrors(robot.Gcode); // Check for any errors that may have occured during the motion
174
176 Assert.That(robot.Gcode.ErrorLogCountGet(), Is.EqualTo(0), "Gcode Error Log Count is not zero. first error: " + robot.Gcode.ErrorLogGet().Message);
177 Assert.That(robot.Gcode.LineCountGet(), Is.EqualTo(gcodeProgram.Count(c => c.Equals('\n'))));
178 VerifyModel(robot.ModelGet(), modelName);
179 }
180
181 [Test]
182 public void ChangingUnits()
183 {
186 const string xLabel = "X-Axis";
187 const string yLabel = "Y-Axis";
188 const string zLabel = "Z-Axis";
189 const string aLabel = "A-Axis";
190 const string bLabel = "B-Axis";
191 const string cLabel = "C-Axis";
192
193 x_axis.UserLabelSet(xLabel);
194 y_axis.UserLabelSet(yLabel);
195 z_axis.UserLabelSet(zLabel);
196 a_axis.UserLabelSet(aLabel);
197 b_axis.UserLabelSet(bLabel);
198 c_axis.UserLabelSet(cLabel);
199
200 // The joint index of each axis is the index within the MultiAxis object.
201 // "X-Axis" has joint index 0
202 // "Y-Axis" has joint index 1
203 // "Z-Axis" has joint index 2
204 // "A-Axis" has joint index 3
205 // "B-Axis" has joint index 4
206 // "C-Axis" has joint index 5
207 Axis[] axes = new Axis[] { x_axis, y_axis, z_axis, a_axis, b_axis, c_axis };
208 jointsMultiAxis.AxesAdd(axes, axes.Length);
209 jointsMultiAxis.ClearFaults();
210
211 const string modelName = "RSI_XYZABC_Centimeters";
212 const LinearUnits units = LinearUnits.Centimeters;
213 const double scaling = 1.0, offset = 0.0;
214 LinearModelBuilder builder = new LinearModelBuilder(modelName);
215 builder.UnitsSet(units);
216 builder.JointAdd(new LinearJointMapping(0, CartesianAxis.X) { ExpectedLabel = xLabel, Scaling = scaling, Offset = offset });
217 builder.JointAdd(new LinearJointMapping(1, CartesianAxis.Y) { ExpectedLabel = yLabel, Scaling = scaling, Offset = offset });
218 builder.JointAdd(new LinearJointMapping(2, CartesianAxis.Z) { ExpectedLabel = zLabel, Scaling = scaling, Offset = offset });
219 builder.JointAdd(new LinearJointMapping(3, CartesianAxis.Roll) { ExpectedLabel = aLabel, Scaling = scaling, Offset = offset });
220 builder.JointAdd(new LinearJointMapping(4, CartesianAxis.Pitch) { ExpectedLabel = bLabel, Scaling = scaling, Offset = offset });
221 builder.JointAdd(new LinearJointMapping(5, CartesianAxis.Yaw) { ExpectedLabel = cLabel, Scaling = scaling, Offset = offset });
222
223 // Create a Robot object with a multi axis containing all joints and the kinematic type
224 robot = Robot.RobotCreate(controller, jointsMultiAxis, builder, MotionController.AxisFrameBufferSizeDefault);
226
227 //NOTE: to use the above kinematic model you must have a gantry (linear 1:1 kinematics) and each linear axis must have its user units scaled to millimeters
228
229 //This will return none. A gcode unit hasn't been established to it will use path units. If path units are not set it will use user units.
230 Console.WriteLine(robot.Gcode.UnitsGet());
231
232 robot.Gcode.AccelerationRateSet(10); //Sets the G-Code acceleration to 10 Centimeters(USER UNITS) per MINUTE sqd
233 robot.Gcode.FeedRateSet(10); //Sets the G-Code velocity to 10 Centimeters(USER UNITS) per MINUTE
234
235 robot.Gcode.UnitsSet(LinearUnits.Inches);//This is the same as executing the G-Code Line G20
236 Console.WriteLine(robot.Gcode.UnitsGet());//This will return Inches as you just set.
237
238
239 robot.Gcode.AccelerationRateSet(10); //Sets the G-Code acceleration to 10 Inches per MINUTE sqd
240 robot.Gcode.FeedRateSet(10); //Sets the G-Code velocity to 10 Inches per MINUTE
241
243 VerifyModel(robot.ModelGet(), modelName, units);
244 }
245}
static void CheckErrors(RapidCodeObject rsiObject)
Check if the RapidCodeObject has any errors.
Helper Functions for checking logged creation errors, starting the network, etc.
void UserLabelSet(const char *const userLabel)
Set the axis User defined Label.
Represents a single axis of motion control. This class provides an interface for commanding motion,...
Definition rsi.h:5643
void FreeAxisLetterSet(const char gcodeLetter, const int32_t freeAxisIndex)=0
Map a letter in a Gcode file to a free axis. It will be used to specify the free axis' motion.
int32_t LineCountGet()=0
Get the number of lines in the last loaded G-Code program.
int32_t ExecutingLineNumberGet()=0
Get the currently executing line number.
LinearUnits UnitsGet()=0
Get the currently active unit as set by G20/G21.
void AccelerationRateSet(double programmingUnitsPerMinuteSquared)=0
REQUIRED before Load() or LoadFile(). Sets the target acceleration for the machine (units/minute^2)....
void UnitsSet(LinearUnits units)=0
Set the currently active unit (same as calling G20/G21)
double DurationGet()=0
Get the time duration required to run the loaded G-Code program in seconds.
void FeedRateSet(double programmingUnitsPerMinute)=0
REQUIRED before Load() or LoadFile() if your g-code does not have 'F' in its contents....
void Load(const char *const text)=0
Load a G-code program from a string.
void Run()=0
Run the loaded G-Code file (or string). The behavior is non-blocking. Use DoneWait() to block.
Handles callbacks for M-codes within a G-code file.
void CallbackRegister(Cartesian::GcodeCallback *callback)=0
G-code callback register.
bool IsRunning()=0
Returns true if a Gcode program is executing, false otherwise.
void UnitsSet(LinearUnits units)
Set the units the built model will use.
void FreeAxisAdd(const ModelAxisMapping &freeAxis)
Map a free axis in the kinematic model. The Axis' DefaultVelocity/Acceleration will be used for free ...
Describes the mathematical kinematic model of a robot.
The Builder for a linear kinematic model. Constructs a single Linear Kinematic Model to use when crea...
void JointAdd(const LinearJointMapping &joint)
adds a joint to the model using the configuration specified within the LinearJoint structure.
uint64_t MotionDoneWait()=0
Waits for a move to complete.
static Robot * RobotCreate(MotionController *controller, MultiAxis *multiAxis, KinematicModelBuilder *builder, uint32_t motionFrameBufferSize)
Create a Robot object to use G-Code, path motion, etc.
void EStop()=0
Commands a joint EStop and clears the loaded moves.
Represents a collection of joints in Cartesian space with forward and inverse kinematics....
void ClearFaults()=0
Clears the MultiAxis fault then the Robot's error bit.
const KinematicModel & ModelGet()=0
Get the model this robot was created with.
static void RobotDelete(MotionController *controller, Robot *robot)
Delete a Robot.
RSI::RapidCode::Cartesian::Gcode * Gcode
An object to load and run Gcode files.
static constexpr int32_t AxisFrameBufferSizeDefault
The default value of the AxisFrameBufferSize, also the minimum allowable value.
Definition rsi.h:845
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:796
void AxisRemoveAll()
Remove all axes from a MultiAxis group.s.
void AxesAdd(Axis **axes, int32_t axisCount)
void ClearFaults()
Clear all faults for an Axis or MultiAxis.
void AmpEnableSet(bool enable)
Enable all amplifiers.
void Abort()
Abort an axis.
const RsiError *const ErrorLogGet()
Get the next RsiError in the log.
int32_t ErrorLogCountGet()
Get the number of software errors in the error log.
make a Callback class and register it with the Gcode object
CartesianAxis
This enum specifies which Cartesian axis a LinearJointMapping maps a robot joint to.
LinearUnits
Unit types. For Cartesian Robot/G-Code use.
The Cartesian namespace.
const char * LineText
The actual line content from the G-code file.
int32_t LineNumber
The line number in the G-code file where the M-code is encountered.
Holds data for the G-code M-code callback mechanism.
Data for adding joint or free-axis mappings when building a kinematic model.