ClearCore Library
Loading...
Searching...
No Matches
DualAxisSynchronized.cpp

Return to SDK Examples for Microchip Studio

1/*
2 * Title: DualAxisSynchronized
3 *
4 * Objective:
5 * This example demonstrates control of two ClearPath-SD motors synchronously
6 * in Step and Direction mode. Use this example when two motors must follow
7 * identical commands (e.g. a mechanically connected dual-axis or gantry).
8 *
9 * Description:
10 * This example enables two motors then commands a repeating series of
11 * synchronized moves. Move status is printed to the USB serial port. This
12 * example commands a max travel of 25600 pulses.
13 *
14 * Requirements:
15 * 1. Two ClearPath motors must be connected, one to Connector M-0 the other to
16 * Connector M-1.
17 * 2. The connected ClearPath motors must be configured through the MSP software
18 * for Step and Direction mode (In MSP select Mode>>Step and Direction).
19 * 3. The ClearPath motors must be set to use the HLFB mode "ASG-Position
20 * w/Measured Torque" with a PWM carrier frequency of 482 Hz through the MSP
21 * software (select Advanced>>High Level Feedback [Mode]... then choose
22 * "ASG-Position w/Measured Torque" from the dropdown, make sure that 482 Hz
23 * is selected in the "PWM Carrier Frequency" dropdown, and hit the OK
24 * button).
25 * 4. If the two motors must spin in opposite directions (i.e. they are mounted
26 * facing different directions), check the "Reverse Direction" checkbox of
27 * one motor in MSP.
28 *
29 * ** Note: Homing is optional, and not required in this operational mode or in
30 * this example. This example makes its first move in the positive direction,
31 * assuming any homing move occurs in the negative direction.
32 *
33 * ** Note: Set the Input Resolution in MSP the same as your motor's Positioning
34 * Resolution spec if you'd like the pulses sent by ClearCore to command a
35 * move of the same number of Encoder Counts, a 1:1 ratio.
36 *
37 * Links:
38 * ** ClearCore Documentation: https://teknic-inc.github.io/ClearCore-library/
39 * ** ClearCore Manual: https://www.teknic.com/files/downloads/clearcore_user_manual.pdf
40 * ** ClearPath Manual (DC Power): https://www.teknic.com/files/downloads/clearpath_user_manual.pdf
41 * ** ClearPath Manual (AC Power): https://www.teknic.com/files/downloads/ac_clearpath-mc-sd_manual.pdf
42 *
43 *
44 * Copyright (c) 2020 Teknic Inc. This work is free to use, copy and distribute under the terms of
45 * the standard MIT permissive software license which can be found at https://opensource.org/licenses/MIT
46 */
47
48#include "ClearCore.h"
49
50// Specify which motors to move.
51// Options are: ConnectorM0, ConnectorM1, ConnectorM2, or ConnectorM3.
52#define motor0 ConnectorM0
53#define motor1 ConnectorM1
54
55// Select the baud rate to match the target serial device
56#define baudRate 9600
57
58// Specify which serial connector to use: ConnectorUsb, ConnectorCOM0, or
59// ConnectorCOM1
60#define SerialPort ConnectorUsb
61
62// This example has built-in functionality to automatically clear motor alerts,
63// including motor shutdowns. Any uncleared alert will cancel and disallow motion.
64// WARNING: enabling automatic alert handling will clear alerts immediately when
65// encountered and return a motor to a state in which motion is allowed. Before
66// enabling this functionality, be sure to understand this behavior and ensure
67// your system will not enter an unsafe state.
68// To enable automatic alert handling, #define HANDLE_ALERTS (1)
69// To disable automatic alert handling, #define HANDLE_ALERTS (0)
70#define HANDLE_ALERTS (0)
71
72// Define the velocity and acceleration limits to be used for each move
73int32_t velocityLimit = 10000; // pulses per sec
74int32_t accelerationLimit = 100000; // pulses per sec^2
75
76// Declares user-defined helper functions.
77// The definition/implementations of these functions are at the bottom of the sketch.
78bool SynchronizedMove(int32_t distance);
79void PrintAlerts();
80void HandleAlerts();
81
82int main() {
83 // Sets the input clocking rate. This normal rate is ideal for ClearPath
84 // step and direction applications.
85 MotorMgr.MotorInputClocking(MotorManager::CLOCK_RATE_NORMAL);
86
87 // Sets all motor connectors into step and direction mode.
88 MotorMgr.MotorModeSet(MotorManager::MOTOR_ALL,
89 Connector::CPM_MODE_STEP_AND_DIR);
90
91 // Put the motor connectors into the HLFB mode to read bipolar PWM (the
92 // correct mode for ASG w/ Measured Torque)
93 motor0.HlfbMode(MotorDriver::HLFB_MODE_HAS_BIPOLAR_PWM);
94 motor1.HlfbMode(MotorDriver::HLFB_MODE_HAS_BIPOLAR_PWM);
95
96 // Set the HFLB carrier frequencies to 482 Hz
97 motor0.HlfbCarrier(MotorDriver::HLFB_CARRIER_482_HZ);
98 motor1.HlfbCarrier(MotorDriver::HLFB_CARRIER_482_HZ);
99
100 // Sets the maximum velocity for each move.
101 motor0.VelMax(velocityLimit);
102 motor1.VelMax(velocityLimit);
103
104 // Sets the maximum acceleration for each move.
105 motor0.AccelMax(accelerationLimit);
106 motor1.AccelMax(accelerationLimit);
107
108 // Sets up serial communication and waits up to 5 seconds for a port to open.
109 // Serial communication is not required for this example to run.
110 SerialPort.Mode(Connector::USB_CDC);
111 SerialPort.Speed(baudRate);
112 uint32_t timeout = 5000;
113 uint32_t startTime = Milliseconds();
114 SerialPort.PortOpen();
115 while (!SerialPort && Milliseconds() - startTime < timeout) {
116 continue;
117 }
118
119 // Enables the motors; homing will begin automatically if enabled in MSP.
120 motor0.EnableRequest(true);
121 SerialPort.SendLine("Motor 0 Enabled");
122 motor1.EnableRequest(true);
123 SerialPort.SendLine("Motor 1 Enabled");
124
125 // Waits for both motors to finish enabling.
126 uint32_t lastStatusTime = Milliseconds();
127 SerialPort.SendLine("Waiting for HLFB...");
128 while ( (motor0.HlfbState() != MotorDriver::HLFB_ASSERTED ||
129 motor1.HlfbState() != MotorDriver::HLFB_ASSERTED) &&
130 !motor0.StatusReg().bit.AlertsPresent &&
131 !motor1.StatusReg().bit.AlertsPresent) {
132 // Periodically prints out why the application is waiting.
133 if (Milliseconds() - lastStatusTime > 1000) {
134 SerialPort.SendLine("Waiting for HLFB to assert on both motors");
135 lastStatusTime = Milliseconds();
136 }
137 }
138 // Check if motor alert occurred during enabling
139 // Clear alert if configured to do so
140 if (motor0.StatusReg().bit.AlertsPresent ||
141 motor1.StatusReg().bit.AlertsPresent) {
142 SerialPort.SendLine("Motor alert detected.");
143 PrintAlerts();
144 if(HANDLE_ALERTS){
145 HandleAlerts();
146 } else {
147 SerialPort.SendLine("Enable automatic alert handling by setting HANDLE_ALERTS to 1.");
148 }
149 SerialPort.SendLine("Enabling may not have completed as expected. Proceed with caution.");
150 SerialPort.SendLine();
151 } else {
152 SerialPort.SendLine("Motor Ready");
153 }
154
155 while (true) {
156 // Move 6400 counts (positive direction) then wait 2000ms.
157 SynchronizedMove(6400);
158 Delay_ms(2000);
159 // Move 19200 counts farther positive, then wait 2000ms.
160 SynchronizedMove(19200);
161 Delay_ms(2000);
162 // Move back 12800 counts (negative direction), then wait 2000ms.
163 SynchronizedMove(-12800);
164 Delay_ms(2000);
165 // Move back 6400 counts (negative direction), then wait 2000ms.
166 SynchronizedMove(-6400);
167 Delay_ms(2000);
168 // Move back to the start (negative 6400 pulses), then wait 2000ms.
169 SynchronizedMove(-6400);
170 Delay_ms(2000);
171 }
172}
173
174/*------------------------------------------------------------------------------
175 * SynchronizedMove
176 *
177 * Moves two motors an incremental distance synchronously.
178 * Prints the move status to the USB serial port
179 * Returns when HLFB asserts (indicating the motor has reached the commanded
180 * position)
181 *
182 * Parameters:
183 * int distance - The distance, in counts, to move
184 *
185 * Returns: True/False depending on whether the moves were successfully
186 * triggered.
187 */
188bool SynchronizedMove(int32_t distance) {
189 // Check if a motor alert is currently preventing motion
190 // Clear alert if configured to do so
191 if (motor0.StatusReg().bit.AlertsPresent || motor1.StatusReg().bit.AlertsPresent ) {
192 SerialPort.SendLine("Motor alert detected.");
193 PrintAlerts();
194 if(HANDLE_ALERTS){
195 HandleAlerts();
196 } else {
197 SerialPort.SendLine("Enable automatic alert handling by setting HANDLE_ALERTS to 1.");
198 }
199 SerialPort.SendLine("Move canceled.");
200 SerialPort.SendLine();
201 return false;
202 }
203
204 SerialPort.Send("Moving distance: ");
205 SerialPort.SendLine(distance);
206
207 // Move both motors the same distance.
208 motor0.Move(distance);
209 motor1.Move(distance);
210
211 // Tell the user that the program will wait for HLFB to assert on both motors
212 SerialPort.SendLine("Waiting for HLFB to assert on both motors");
213
214 // Wait until both motors complete their moves.
215 uint32_t lastStatusTime = Milliseconds();
216 while ( (!motor0.StepsComplete() || motor0.HlfbState() != MotorDriver::HLFB_ASSERTED ||
217 !motor1.StepsComplete() || motor1.HlfbState() != MotorDriver::HLFB_ASSERTED) &&
218 !motor0.StatusReg().bit.AlertsPresent && !motor1.StatusReg().bit.AlertsPresent ){
219 continue;
220 }
221
222 // Check if motor alert occurred during move
223 // Clear alert if configured to do so
224 if (motor0.StatusReg().bit.AlertsPresent || motor1.StatusReg().bit.AlertsPresent){
225 motor0.MoveStopAbrupt();
226 motor1.MoveStopAbrupt();
227 SerialPort.SendLine("Motor alert detected.");
228 PrintAlerts();
229 if(HANDLE_ALERTS){
230 HandleAlerts();
231 } else {
232 SerialPort.SendLine("Enable automatic fault handling by setting HANDLE_ALERTS to 1.");
233 }
234 SerialPort.SendLine("Motion may not have completed as expected. Proceed with caution.");
235 SerialPort.SendLine();
236 return false;
237 } else {
238 SerialPort.SendLine("Move Done");
239 return true;
240 }
241}
242
243
244/*------------------------------------------------------------------------------
245 * PrintAlerts
246 *
247 * Prints active alerts.
248 *
249 * Parameters:
250 * requires "motor0" and "motor1" to be defined as ClearCore motor connectors
251 *
252 * Returns:
253 * none
254 */
255 void PrintAlerts(){
256 // report status of alerts on motor0
257 SerialPort.SendLine("Alerts present on motor0: ");
258 if(motor0.AlertReg().bit.MotionCanceledInAlert){
259 SerialPort.SendLine(" MotionCanceledInAlert "); }
260 if(motor0.AlertReg().bit.MotionCanceledPositiveLimit){
261 SerialPort.SendLine(" MotionCanceledPositiveLimit "); }
262 if(motor0.AlertReg().bit.MotionCanceledNegativeLimit){
263 SerialPort.SendLine(" MotionCanceledNegativeLimit "); }
264 if(motor0.AlertReg().bit.MotionCanceledSensorEStop){
265 SerialPort.SendLine(" MotionCanceledSensorEStop "); }
266 if(motor0.AlertReg().bit.MotionCanceledMotorDisabled){
267 SerialPort.SendLine(" MotionCanceledMotorDisabled "); }
268 if(motor0.AlertReg().bit.MotorFaulted){
269 SerialPort.SendLine(" MotorFaulted ");
270 }
271
272 // report status of alerts on motor1
273 SerialPort.SendLine("Alerts present on motor1: ");
274 if(motor1.AlertReg().bit.MotionCanceledInAlert){
275 SerialPort.SendLine(" MotionCanceledInAlert "); }
276 if(motor1.AlertReg().bit.MotionCanceledPositiveLimit){
277 SerialPort.SendLine(" MotionCanceledPositiveLimit "); }
278 if(motor1.AlertReg().bit.MotionCanceledNegativeLimit){
279 SerialPort.SendLine(" MotionCanceledNegativeLimit "); }
280 if(motor1.AlertReg().bit.MotionCanceledSensorEStop){
281 SerialPort.SendLine(" MotionCanceledSensorEStop "); }
282 if(motor1.AlertReg().bit.MotionCanceledMotorDisabled){
283 SerialPort.SendLine(" MotionCanceledMotorDisabled "); }
284 if(motor1.AlertReg().bit.MotorFaulted){
285 SerialPort.SendLine(" MotorFaulted ");
286 }
287 }
288//------------------------------------------------------------------------------
289
290
291/*------------------------------------------------------------------------------
292 * HandleAlerts
293 *
294 * Clears alerts, including motor faults.
295 * Faults are cleared by cycling enable to the motor.
296 * Alerts are cleared by clearing the ClearCore alert register directly.
297 *
298 * Parameters:
299 * requires "motor0" and "motor1" to be defined as ClearCore motor connectors
300 *
301 * Returns:
302 * none
303 */
304 void HandleAlerts(){
305 // for each motor, if a motor fault is present, clear it by cycling enable
306 if(motor0.AlertReg().bit.MotorFaulted){
307 SerialPort.SendLine("Faults present on motor0. Cycling enable signal to motor to clear faults.");
308 motor0.EnableRequest(false);
309 Delay_ms(10);
310 motor0.EnableRequest(true);
311 }
312 if(motor1.AlertReg().bit.MotorFaulted){
313 SerialPort.SendLine("Faults present on motor1. Cycling enable signal to motor to clear faults.");
314 motor1.EnableRequest(false);
315 Delay_ms(10);
316 motor1.EnableRequest(true);
317 }
318 // clear alerts
319 SerialPort.SendLine("Clearing alerts on both motors.");
320 motor0.ClearAlerts();
321 motor1.ClearAlerts();
322 }
323//------------------------------------------------------------------------------
void Delay_ms(uint32_t ms)
Blocks operations for ms milliseconds.
Definition SysTiming.h:287
uint32_t Milliseconds(void)
Number of milliseconds since the ClearCore was initialized.
bool MotorInputClocking(MotorClockRates newRate)
Sets the output step rate for the motor step generators.
bool MotorModeSet(MotorPair motorPair, Connector::ConnectorModes newMode)
Sets the operational mode for the specified MotorDriver connectors.