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

Return to SDK Examples for Microchip Studio

1/*
2 * Title: ManualVelocity
3 *
4 * Objective:
5 * This example demonstrates control of the ClearPath-MC operational mode
6 * Manual Velocity Control.
7 *
8 * Description:
9 * This example enables a ClearPath motor and executes a repeating pattern of
10 * bidirectional velocity moves. During operation, various move statuses are
11 * written to the USB serial port.
12 *
13 * Requirements:
14 * 1. A ClearPath motor must be connected to Connector M-0.
15 * 2. The connected ClearPath motor must be configured through the MSP software
16 * for Manual Velocity Control mode (In MSP select Mode>>Velocity>>Manual
17 * Velocity Control, then hit the OK button).
18 * 3. In the MSP software:
19 * * Define a Max Clockwise and Counter-Clockwise (CW/CCW) Velocity (On the
20 * main MSP window fill in the textboxes labeled "Max CW Velocity (RPM)"
21 * and "Max CCW Velocity (RPM)"). Any velocity commanded outside of this
22 * range will be rejected.
23 * * Set the Velocity Resolution to 2 (On the main MSP window check the
24 * textbox labeled "Velocity Resolution (RPM per knob count)" 2 is
25 * default). This means the commanded velocity will always be a multiple
26 * of 2. For finer resolution, lower this value and change
27 * velocityResolution in the sketch below to match.
28 * * Set Knob Direction to As-Wired, and check the Has Detents box (On the
29 * main MSP window check the dropdown labeled "Knob Direction" and the
30 * checkbox directly below it labeled "Has Detents").
31 * * On the main MSP window set the dropdown labeled "On Enable..." to be
32 * "Zero Velocity".
33 * * Set the HLFB mode to "ASG-Velocity w/Measured Torque" with a PWM carrier
34 * frequency of 482 Hz through the MSP software (select Advanced>>High
35 * Level Feedback [Mode]... then choose "ASG-Velocity w/Measured Torque"
36 * from the dropdown, make sure that 482 Hz is selected in the "PWM Carrier
37 * Frequency" dropdown, and hit the OK button).
38 *
39 * Links:
40 * ** ClearCore Documentation: https://teknic-inc.github.io/ClearCore-library/
41 * ** ClearCore Manual: https://www.teknic.com/files/downloads/clearcore_user_manual.pdf
42 * ** ClearPath Manual (DC Power): https://www.teknic.com/files/downloads/clearpath_user_manual.pdf
43 * ** ClearPath Manual (AC Power): https://www.teknic.com/files/downloads/ac_clearpath-mc-sd_manual.pdf
44 * ** ClearPath Mode Informational Video: https://www.teknic.com/watch-video/#OpMode6
45 *
46 *
47 * Copyright (c) 2020 Teknic Inc. This work is free to use, copy and distribute under the terms of
48 * the standard MIT permissive software license which can be found at https://opensource.org/licenses/MIT
49 */
50
51#include "ClearCore.h"
52
53// Defines the motor's connector as ConnectorM0
54#define motor ConnectorM0
55
56// Select the baud rate to match the target device.
57#define baudRate 9600
58
59// Specify which serial to use: ConnectorUsb, ConnectorCOM0, or ConnectorCOM1.
60#define SerialPort ConnectorUsb
61
62// This example has built-in functionality to automatically clear motor faults.
63// Any uncleared fault will cancel and disallow motion.
64// WARNING: enabling automatic fault handling will clear faults 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 fault handling, #define HANDLE_MOTOR_FAULTS (1)
69// To disable automatic fault handling, #define HANDLE_MOTOR_FAULTS (0)
70#define HANDLE_MOTOR_FAULTS (0)
71
72// This is the variable used to keep track of the current commanded velocity
73double commandedVelocity = 0;
74
75// A reference to the maximum clockwise and counter-clockwise velocities set in
76// the MSP software. These must match the values in MSP
77int32_t maxVelocityCW = 1000;
78int32_t maxVelocityCCW = 1000;
79
80// Each velocity commanded will be a multiple of this value, which must match
81// the Velocity Resolution value in MSP. Use a lower value here (and in MSP) to
82// command velocity with a finer resolution
83double velocityResolution = 2.0;
84
85// Declares user-defined helper functions.
86// The definition/implementations of these functions are at the bottom of the sketch.
87bool MoveAtVelocity(double velocity);
88void HandleMotorFaults();
89
90int main() {
91 // Set all motor connectors to the correct mode for Manual Velocity
92 // mode.
93 MotorMgr.MotorModeSet(MotorManager::MOTOR_ALL,
94 Connector::CPM_MODE_A_DIRECT_B_DIRECT);
95
96 // Set the motor's HLFB mode to bipolar PWM
97 motor.HlfbMode(MotorDriver::HLFB_MODE_HAS_BIPOLAR_PWM);
98 // Set the HFLB carrier frequency to 482 Hz
99 motor.HlfbCarrier(MotorDriver::HLFB_CARRIER_482_HZ);
100
101 // Enforces the state of the motor's A and B inputs before enabling
102 // the motor.
103 motor.MotorInAState(false);
104 motor.MotorInBState(false);
105
106 // Sets up serial communication and waits up to 5 seconds for a port to open.
107 // Serial communication is not required for this example to run.
108 SerialPort.Mode(Connector::USB_CDC);
109 SerialPort.Speed(baudRate);
110 uint32_t timeout = 5000;
111 uint32_t startTime = Milliseconds();
112 SerialPort.PortOpen();
113 while (!SerialPort && Milliseconds() - startTime < timeout) {
114 continue;
115 }
116
117 // Enables the motor
118 motor.EnableRequest(true);
119 SerialPort.SendLine("Motor Enabled");
120
121 // Waits for HLFB to assert
122 SerialPort.SendLine("Waiting for HLFB...");
123 SerialPort.SendLine("Waiting for HLFB...");
124 while (motor.HlfbState() != MotorDriver::HLFB_ASSERTED &&
125 !motor.StatusReg().bit.MotorInFault) {
126 continue;
127 }
128 // Check if a motor faulted during enabling
129 // Clear fault if configured to do so
130 if (motor.StatusReg().bit.MotorInFault) {
131 SerialPort.SendLine("Motor fault detected.");
132 if(HANDLE_MOTOR_FAULTS){
133 HandleMotorFaults();
134 } else {
135 SerialPort.SendLine("Enable automatic fault handling by setting HANDLE_MOTOR_FAULTS to 1.");
136 }
137 SerialPort.SendLine("Enabling may not have completed as expected. Proceed with caution.");
138 SerialPort.SendLine();
139 } else {
140 SerialPort.SendLine("Motor Ready");
141 }
142
143 while (true) {
144 // Spin at 500 RPM in the CCW direction.
145 MoveAtVelocity(500); // See below for the detailed function definition.
146 // Hold the velocity for 5 seconds before issuing a new command.
147 Delay_ms(5000);
148
149 // Spin at 100 RPM in the CW direction.
150 MoveAtVelocity(-100);
151 Delay_ms(5000);
152
153 // Spin at 750 RPM in the CW direction.
154 MoveAtVelocity(-750);
155 Delay_ms(5000);
156
157 // Spin at 1000 RPM in the CCW direction.
158 MoveAtVelocity(1000);
159 Delay_ms(5000);
160
161 // Command 0 RPM, the motor shaft is stationary.
162 MoveAtVelocity(0);
163 Delay_ms(5000);
164 }
165}
166
167/*------------------------------------------------------------------------------
168 * MoveAtVelocity
169 *
170 * Triggers a quadrature output commanding the desired velocity.
171 * Prints the velocity and move status to the USB serial port.
172 * Returns when HLFB asserts (indicating move has successfully completed).
173 *
174 * Parameters:
175 * double velocity - The velocity in RPM to command
176 *
177 * Returns: True/False depending on whether a new velocity was reached
178 */
179bool MoveAtVelocity(double velocity) {
180 // If the same velocity is commanded there's nothing to do.
181 if (velocity == commandedVelocity) {
182 return false;
183 }
184
185 // Check to see if the requested velocity exceeds the valid range.
186 if (velocity > maxVelocityCCW || velocity < -maxVelocityCW) {
187 SerialPort.Send("An invalid velocity of ");
188 SerialPort.Send(velocity);
189 SerialPort.SendLine(" RPM has been requested.");
190 return false;
191 }
192
193 // Check if a motor fault is currently preventing motion
194 // Clear fault if configured to do so
195 if (motor.StatusReg().bit.MotorInFault) {
196 if(HANDLE_MOTOR_FAULTS){
197 SerialPort.SendLine("Motor fault detected. Move canceled.");
198 HandleMotorFaults();
199 } else {
200 SerialPort.SendLine("Motor fault detected. Move canceled. Enable automatic fault handling by setting HANDLE_MOTOR_FAULTS to 1.");
201 }
202 return false;
203 }
204
205 SerialPort.Send("Commanding ");
206 SerialPort.Send(velocity);
207 SerialPort.SendLine(" RPM");
208
209 // Determine which order the quadrature must be sent by determining if the
210 // new velocity is greater or less than the previously commanded velocity
211 // If greater, Input A begins the quadrature. If less, Input B begins the
212 // quadrature.
213 int32_t currentVelocityRounded = round(commandedVelocity / velocityResolution);
214 int32_t targetVelocityRounded = round(velocity / velocityResolution);
215 int32_t velocityDifference = labs(targetVelocityRounded - currentVelocityRounded);
216 for (int32_t i = 0; i < velocityDifference; i++) {
217 if (velocity > commandedVelocity) {
218 // Toggle Input A to begin the quadrature signal.
219 motor.MotorInAState(true);
220 // Command a 5 microsecond delay to ensure proper signal timing.
221 Delay_us(5);
222 motor.MotorInBState(true);
223 Delay_us(5);
224 motor.MotorInAState(false);
225 Delay_us(5);
226 motor.MotorInBState(false);
227 Delay_us(5);
228 }
229 else {
230 motor.MotorInBState(true);
231 Delay_us(5);
232 motor.MotorInAState(true);
233 Delay_us(5);
234 motor.MotorInBState(false);
235 Delay_us(5);
236 motor.MotorInAState(false);
237 Delay_us(5);
238 }
239 }
240
241 // Keeps track of the new commanded velocity
242 commandedVelocity = velocity;
243
244 // Waits for HLFB to assert (signaling the motor has successfully reached
245 // its target velocity).
246 SerialPort.SendLine("Ramping Speed... Waiting for HLFB");
247 while (motor.HlfbState() != MotorDriver::HLFB_ASSERTED &&
248 !motor.StatusReg().bit.MotorInFault) {
249 continue;
250 }
251 // Check if a motor faulted during move
252 // Clear fault if configured to do so
253 if (motor.StatusReg().bit.MotorInFault) {
254 SerialPort.SendLine("Motor fault detected.");
255 if(HANDLE_MOTOR_FAULTS){
256 HandleMotorFaults();
257 } else {
258 SerialPort.SendLine("Enable automatic fault handling by setting HANDLE_MOTOR_FAULTS to 1.");
259 }
260 SerialPort.SendLine("Motion may not have completed as expected. Proceed with caution.");
261 SerialPort.SendLine();
262 return false;
263 } else {
264 SerialPort.SendLine("Move Done");
265 return true;
266 }
267
268 SerialPort.SendLine("Target Velocity Reached");
269 return true;
270}
271//------------------------------------------------------------------------------
272
273/*------------------------------------------------------------------------------
274 * HandleMotorFaults
275 *
276 * Clears motor faults by cycling enable to the motor.
277 * Assumes motor is in fault
278 * (this function is called when motor.StatusReg.MotorInFault == true)
279 *
280 * Parameters:
281 * requires "motor" to be defined as a ClearCore motor connector
282 *
283 * Returns:
284 * none
285 */
286 void HandleMotorFaults(){
287 SerialPort.SendLine("Handling fault: clearing faults by cycling enable signal to motor.");
288 motor.EnableRequest(false);
289 Delay_ms(10);
290 motor.EnableRequest(true);
291 Delay_ms(100);
292 }
293//------------------------------------------------------------------------------
void Delay_ms(uint32_t ms)
Blocks operations for ms milliseconds.
Definition SysTiming.h:287
void Delay_us(uint32_t usec)
Blocks for operations usec microseconds.
Definition SysTiming.h:296
uint32_t Milliseconds(void)
Number of milliseconds since the ClearCore was initialized.
bool MotorModeSet(MotorPair motorPair, Connector::ConnectorModes newMode)
Sets the operational mode for the specified MotorDriver connectors.