The RMP Motion Controller APIs
GcodeMotion.cs
1
28using RSI.RapidCode.dotNET; // Import our RapidCode Library.
29using NUnit.Framework;
30using System;
31using System.Linq;
32using System.Threading;
33using System.IO;
34using System.Runtime.InteropServices;
35
36#if DOXYGEN // RSI internal documentation use only
37using RSI.RapidCode;
39#endif
40
43{
44 public override void Execute(GcodeCallbackData data)
45 {
46 Console.WriteLine("G-Code Callback executed: " + data.LineNumber + " " + data.LineText);
47
48 // if you want to nofity the Gcode object that there's an error processing, set its error details:
49 // data.UserError.number = RSIErrorMessage.RSI_ERROR_MESSAGE_DYNAMIC;
50 // data.UserError.text = "This is an error from the callback.";
51 }
52}
53
54[TestFixture]
55[Category("Software")]
56public class GcodeMotion : SampleAppTestBase
57{
58 [SetUp]
59 public void Setup()
60 {
61 jointsMultiAxis?.AxisRemoveAll();
62 }
63
64 [TearDown]
65 public void Teardown()
66 {
67 robot?.EStop();
68 robot?.MotionDoneWait();
69 robot?.ClearFaults();
70 Robot.RobotDelete(controller, robot);
71 robot = null;
72
73 jointsMultiAxis?.Abort();
74 Thread.Sleep(50);
75 jointsMultiAxis?.ClearFaults();
76 }
77
78 private void VerifyModel(KinematicModel model, string expectedName, LinearUnits expectedUnits = LinearUnits.None)
79 {
80 var actualUnits = model.UnitsGet();
81 Assert.That(actualUnits, Is.EqualTo(expectedUnits), $"Expected model units to be '{expectedUnits}' but was '{actualUnits}' instead!");
82 var actualName = model.NameGet();
83 Assert.That(actualName, Is.EqualTo(expectedName), $"Expected model name to be '{expectedName}' but was '{actualName}' instead!");
84 }
85
86 [Test]
87 public void GcodeBasic()
88 {
91 string gcodeProgram = "G91; Sets the programming mode to RELATIVE\n" +
92 "G64; Turns off exact stop mode(Default)\n" +
93 "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" +
94 "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" +
95 "M80; Show how to use an M-code with GcodeCallback!\n";
96
97 // We assume the axes have been confgured and homed properly prior this this program.
98 const string xLabel = "X-Axis";
99 const string yLabel = "Y-Axis";
100 const string zLabel = "Z-Axis";
101 const string aLabel = "A-Axis";
102
103 x_axis.UserLabelSet(xLabel);
104 y_axis.UserLabelSet(yLabel);
105 z_axis.UserLabelSet(zLabel);
106 a_axis.UserLabelSet(aLabel);
107
108 // The joint index of each axis is the index within the MultiAxis object.
109 // "X-Axis" has joint index 0
110 // "Y-Axis" has joint index 1
111 // "Z-Axis" has joint index 2
112 // "A-Axis" has joint index 3
113 Axis[] axes = new Axis[] { x_axis, y_axis, z_axis, a_axis };
114 jointsMultiAxis.AxesAdd(axes, axes.Length);
115 jointsMultiAxis.ClearFaults();
116 jointsMultiAxis.AmpEnableSet(true);
117
118 const string modelName = "RSI_XYZA";
119 const double scaling = 1.0, offset = 0.0;
120 LinearModelBuilder builder = new LinearModelBuilder(modelName);
121 builder.JointAdd(new LinearJointMapping(0, CartesianAxis.X) { ExpectedLabel = xLabel, Scaling = scaling, Offset = offset });
122 builder.JointAdd(new LinearJointMapping(1, CartesianAxis.Y) { ExpectedLabel = yLabel, Scaling = scaling, Offset = offset });
123 builder.JointAdd(new LinearJointMapping(2, CartesianAxis.Z) { ExpectedLabel = zLabel, Scaling = scaling, Offset = offset });
124 builder.FreeAxisAdd(new ModelAxisMapping(3) { ExpectedLabel = aLabel, Scaling = scaling, Offset = offset }); // Add a free axis.
125
126 // Create a Robot object with a multi axis containing all joints and the kinematic type
127 robot = Robot.RobotCreate(controller, jointsMultiAxis, builder, MotionController.AxisFrameBufferSizeDefault);
129
130 robot.Gcode.AccelerationRateSet(1000); // UserUnits per minute squared
131
132 // 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.
133 robot.Gcode.FreeAxisLetterSet('A', 0);
134
136 robot.Gcode.CallbackRegister(callback); // Register a callback to be called when the Gcode encounters any M-code command
137
138 try
139 {
140 robot.Gcode.Load(gcodeProgram); // Loads in the string and prepairs it for execution
141 }
142 catch (Exception e)
143 {
144 if (robot.Gcode.SyntaxErrorLineNumberGet() != -1)
145 {
146 // LineNumberGet retusns positive when a gcode errors exists on a known line. Or if the exception is of type PathLine or GcodeLine
147 Console.WriteLine("Error on line: " + robot.Gcode.SyntaxErrorLineNumberGet() + "Details: " + e.Message);
148 }
149 else
150 {
151 Console.WriteLine("Error: " + e.Message);
152 }
153 }
154 // print some details about the upcoming motion
155 Console.WriteLine("G-Code Line Count: " + robot.Gcode.LineCountGet());
156 Console.WriteLine("G-Code Error Log Count: " + robot.Gcode.ErrorLogCountGet());
157 Console.WriteLine("G-code estimated run time: " + robot.Gcode.DurationGet() + " seconds");
158
159 robot.Gcode.Run(); // Starts the motion. Calling with the false arguement for non blocking behavior
160 Int64 activeLineNumber = 0;
161 do
162 {
163 Thread.Sleep(200);
164 if (activeLineNumber != robot.Gcode.ExecutingLineNumberGet()) // only write if we are on a new line
165 {
166 activeLineNumber = robot.Gcode.ExecutingLineNumberGet();
167 Console.WriteLine("G-Code Line Number: " + activeLineNumber);
168 }
169 } while (robot.Gcode.IsRunning());
171
173 Assert.That(robot.Gcode.ErrorLogCountGet(), Is.EqualTo(0), "Gcode Error Log Count is not zero. first error: " + robot.Gcode.ErrorLogGet().Message);
174 Assert.AreEqual(gcodeProgram.Count(c => c.Equals('\n')), robot.Gcode.LineCountGet());
175 VerifyModel(robot.ModelGet(), modelName);
176 }
177
178 [Test]
179 public void ChangingUnits()
180 {
183 const string xLabel = "X-Axis";
184 const string yLabel = "Y-Axis";
185 const string zLabel = "Z-Axis";
186 const string aLabel = "A-Axis";
187 const string bLabel = "B-Axis";
188 const string cLabel = "C-Axis";
189
190 x_axis.UserLabelSet(xLabel);
191 y_axis.UserLabelSet(yLabel);
192 z_axis.UserLabelSet(zLabel);
193 a_axis.UserLabelSet(aLabel);
194 b_axis.UserLabelSet(bLabel);
195 c_axis.UserLabelSet(cLabel);
196
197 // The joint index of each axis is the index within the MultiAxis object.
198 // "X-Axis" has joint index 0
199 // "Y-Axis" has joint index 1
200 // "Z-Axis" has joint index 2
201 // "A-Axis" has joint index 3
202 // "B-Axis" has joint index 4
203 // "C-Axis" has joint index 5
204 Axis[] axes = new Axis[] { x_axis, y_axis, z_axis, a_axis, b_axis, c_axis };
205 jointsMultiAxis.AxesAdd(axes, axes.Length);
206 jointsMultiAxis.ClearFaults();
207
208 const string modelName = "RSI_XYZABC_Centimeters";
209 const LinearUnits units = LinearUnits.Centimeters;
210 const double scaling = 1.0, offset = 0.0;
211 LinearModelBuilder builder = new LinearModelBuilder(modelName);
212 builder.UnitsSet(units);
213 builder.JointAdd(new LinearJointMapping(0, CartesianAxis.X) { ExpectedLabel = xLabel, Scaling = scaling, Offset = offset });
214 builder.JointAdd(new LinearJointMapping(1, CartesianAxis.Y) { ExpectedLabel = yLabel, Scaling = scaling, Offset = offset });
215 builder.JointAdd(new LinearJointMapping(2, CartesianAxis.Z) { ExpectedLabel = zLabel, Scaling = scaling, Offset = offset });
216 builder.JointAdd(new LinearJointMapping(3, CartesianAxis.Roll) { ExpectedLabel = aLabel, Scaling = scaling, Offset = offset });
217 builder.JointAdd(new LinearJointMapping(4, CartesianAxis.Pitch) { ExpectedLabel = bLabel, Scaling = scaling, Offset = offset });
218 builder.JointAdd(new LinearJointMapping(5, CartesianAxis.Yaw) { ExpectedLabel = cLabel, Scaling = scaling, Offset = offset });
219
220 // Create a Robot object with a multi axis containing all joints and the kinematic type
221 robot = Robot.RobotCreate(controller, jointsMultiAxis, builder, MotionController.AxisFrameBufferSizeDefault);
223
224 //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
225
226 //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.
227 Console.WriteLine(robot.Gcode.UnitsGet());
228
229 robot.Gcode.AccelerationRateSet(10); //Sets the G-Code acceleration to 10 Centimeters(USER UNITS) per MINUTE sqd
230 robot.Gcode.FeedRateSet(10); //Sets the G-Code velocity to 10 Centimeters(USER UNITS) per MINUTE
231
232 robot.Gcode.UnitsSet(LinearUnits.Inches);//This is the same as executing the G-Code Line G20
233 Console.WriteLine(robot.Gcode.UnitsGet());//This will return Inches as you just set.
234
235
236 robot.Gcode.AccelerationRateSet(10); //Sets the G-Code acceleration to 10 Inches per MINUTE sqd
237 robot.Gcode.FeedRateSet(10); //Sets the G-Code velocity to 10 Inches per MINUTE
238
240 VerifyModel(robot.ModelGet(), modelName, units);
241 }
242}
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:5664
int32_t LineCountGet()=0
Get the number of lines in the last loaded G-Code program.
int32_t SyntaxErrorLineNumberGet()=0
Gets the line number of any errors in the G-Code syntax.
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
Sets the target acceleration for the machine (units/minute^2). Should be set apprpriately based on yo...
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 FreeAxisLetterSet(const char gcodeLetter, const int freeAxisIndex)=0
Map a letter in a Gcode file to a free axis. It will be used to specify the free axis' motion.
void FeedRateSet(double programmingUnitsPerMinute)=0
Sets the target feed rate for the machine (units/minute).
void Run()=0
Run the loaded G-Code file (or string). The behavior is non-blocking. Use Robot.MotionDoneWait() to b...
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.
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 Visit our Topic Page for more information.
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:814
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:762
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 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.