
Telescope motorised focuser based on the moonlite protocol, indilib's indi_monlite_focuser compliant. WIP
main.cpp@8:ccfbd168f077, 2018-08-05 (annotated)
- Committer:
- rakware
- Date:
- Sun Aug 05 09:19:46 2018 +0000
- Revision:
- 8:ccfbd168f077
- Parent:
- 7:30dcdf917330
using Ticker to set motor speed
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rakware | 2:c75920ffd4b1 | 1 | #include "mbed.h" //uses https://github.com/ARMmbed/mbed-os/ |
rakware | 2:c75920ffd4b1 | 2 | |
rakware | 3:20b077586e4e | 3 | DigitalOut led(LED1); //board led, just for fun |
rakware | 3:20b077586e4e | 4 | |
rakware | 2:c75920ffd4b1 | 5 | Serial pc(USBTX, USBRX); // tx, rx pc control over usb |
rakware | 0:c990fafbe0fc | 6 | |
rakware | 3:20b077586e4e | 7 | uint16_t gn = 0; //position to move to |
rakware | 3:20b077586e4e | 8 | uint16_t gp = 0; //current position |
rakware | 3:20b077586e4e | 9 | uint16_t temperature = 255; //hardcoded for now //TODO |
rakware | 3:20b077586e4e | 10 | |
rakware | 8:ccfbd168f077 | 11 | bool move = false; |
rakware | 2:c75920ffd4b1 | 12 | |
rakware | 3:20b077586e4e | 13 | uint16_t step_delay = 256; |
rakware | 5:8965c2919afb | 14 | |
rakware | 5:8965c2919afb | 15 | //minimum motor speed that will get doubled 5 times to result maximum motor speed |
rakware | 8:ccfbd168f077 | 16 | //eg: for a value of 16 there will be 5 speeds as follows 16*1,16*2,16*4,16*8,16*16 |
rakware | 8:ccfbd168f077 | 17 | //eg: for a value of 16 there will be 5 speeds as follows 16,32,64,128,256 |
rakware | 8:ccfbd168f077 | 18 | uint8_t min_motor_pps = 16; //TODO use max pps since it might be more intuitive? |
rakware | 4:2235d6d01ca5 | 19 | |
rakware | 3:20b077586e4e | 20 | |
rakware | 3:20b077586e4e | 21 | char ml_in[256]; |
rakware | 3:20b077586e4e | 22 | uint8_t idx = 0; |
rakware | 3:20b077586e4e | 23 | |
rakware | 8:ccfbd168f077 | 24 | Thread serial_thread, motor_thread; |
rakware | 8:ccfbd168f077 | 25 | Ticker m_speed; |
rakware | 0:c990fafbe0fc | 26 | |
rakware | 2:c75920ffd4b1 | 27 | void led_blink() |
rakware | 2:c75920ffd4b1 | 28 | { |
rakware | 2:c75920ffd4b1 | 29 | while (true) { |
rakware | 2:c75920ffd4b1 | 30 | led = !led; |
rakware | 2:c75920ffd4b1 | 31 | wait(1); |
rakware | 2:c75920ffd4b1 | 32 | } |
rakware | 2:c75920ffd4b1 | 33 | } |
rakware | 2:c75920ffd4b1 | 34 | |
rakware | 0:c990fafbe0fc | 35 | |
rakware | 5:8965c2919afb | 36 | //motor control with MP6500 https://www.pololu.com/product/2968 |
rakware | 5:8965c2919afb | 37 | //aproximate formula for motor current control pwm.pulsewidth% = (motor_rated_current_in_amps-2.2)/-2.079, so for our 330ma motor we use pw = (0.330-2.2)/-2.079 |
rakware | 5:8965c2919afb | 38 | // https://www.pololu.com/product/2968#lightbox-picture0J8398;main-pictures , 1 kHz or greater, I2 set to low |
rakware | 4:2235d6d01ca5 | 39 | //D2,D3,D4,D5,D6,D7,D8,D9 - DIR, STEP, SLP, I2, I1, MS2, MS1, EN |
rakware | 4:2235d6d01ca5 | 40 | |
rakware | 4:2235d6d01ca5 | 41 | DigitalOut dir(D2); |
rakware | 4:2235d6d01ca5 | 42 | DigitalOut step(D3); |
rakware | 4:2235d6d01ca5 | 43 | DigitalOut slp(D4); //pull high to enable operation |
rakware | 5:8965c2919afb | 44 | DigitalOut i2(D5); //set low to enable pwm power control |
rakware | 4:2235d6d01ca5 | 45 | PwmOut i1(D6); //MP6500 power limit control |
rakware | 8:ccfbd168f077 | 46 | DigitalOut ms2(D7); //D7 and D8 are PC_14 and PC_15 N/C oscillator pins, hence this is full step only //TODO |
rakware | 4:2235d6d01ca5 | 47 | DigitalOut ms1(D8); //set low for FULL or high for HALF, only use MS1 to be moonlite compliant ? |
rakware | 4:2235d6d01ca5 | 48 | DigitalOut en(D9); //pulled low by the motor driver, default enables operation |
rakware | 4:2235d6d01ca5 | 49 | |
rakware | 5:8965c2919afb | 50 | float motor_max_amps = 0.33f; |
rakware | 4:2235d6d01ca5 | 51 | |
rakware | 7:30dcdf917330 | 52 | float pw = (motor_max_amps-2.2f)/-2.079f; //https://www.pololu.com/product/2968#lightbox-picture0J8398;main-pictures |
rakware | 0:c990fafbe0fc | 53 | |
rakware | 4:2235d6d01ca5 | 54 | void mp6500() //TODO enable/disable motor |
rakware | 4:2235d6d01ca5 | 55 | { |
rakware | 4:2235d6d01ca5 | 56 | dir = 0; |
rakware | 4:2235d6d01ca5 | 57 | step = 0; |
rakware | 4:2235d6d01ca5 | 58 | slp = 1; |
rakware | 4:2235d6d01ca5 | 59 | i2 = 0; |
rakware | 4:2235d6d01ca5 | 60 | i1.period(0.001f); //1kHz period |
rakware | 8:ccfbd168f077 | 61 | i1.write(1.0f); //start with lowest power since we're idle |
rakware | 4:2235d6d01ca5 | 62 | ms2 = 0; |
rakware | 5:8965c2919afb | 63 | ms1 = 1; |
rakware | 4:2235d6d01ca5 | 64 | en = 0; |
rakware | 4:2235d6d01ca5 | 65 | } |
rakware | 4:2235d6d01ca5 | 66 | |
rakware | 4:2235d6d01ca5 | 67 | |
rakware | 8:ccfbd168f077 | 68 | void m_step() |
rakware | 3:20b077586e4e | 69 | { |
rakware | 2:c75920ffd4b1 | 70 | |
rakware | 8:ccfbd168f077 | 71 | //while (true) { |
rakware | 3:20b077586e4e | 72 | |
rakware | 3:20b077586e4e | 73 | if(move) { |
rakware | 5:8965c2919afb | 74 | |
rakware | 5:8965c2919afb | 75 | i1.write(pw); //set defined current motor while moving |
rakware | 5:8965c2919afb | 76 | |
rakware | 3:20b077586e4e | 77 | if(gp > gn) { |
rakware | 3:20b077586e4e | 78 | |
rakware | 4:2235d6d01ca5 | 79 | dir = 0; |
rakware | 5:8965c2919afb | 80 | wait_us(1); |
rakware | 5:8965c2919afb | 81 | //led = !led; |
rakware | 4:2235d6d01ca5 | 82 | step = !step; |
rakware | 5:8965c2919afb | 83 | wait_us(1); //mp6500 |
rakware | 5:8965c2919afb | 84 | //led = !led; |
rakware | 4:2235d6d01ca5 | 85 | step = !step; |
rakware | 5:8965c2919afb | 86 | wait_us(1); |
rakware | 8:ccfbd168f077 | 87 | //https://os.mbed.com/docs/v5.9/mbed-os-api-doxy/mbed__wait__api_8h_source.html use Thread::wait()? |
rakware | 8:ccfbd168f077 | 88 | //wait((step_delay/1.024)/min_motor_pps/250); |
rakware | 3:20b077586e4e | 89 | gp--; |
rakware | 3:20b077586e4e | 90 | |
rakware | 3:20b077586e4e | 91 | } else if (gp < gn) { |
rakware | 0:c990fafbe0fc | 92 | |
rakware | 4:2235d6d01ca5 | 93 | dir = 1; |
rakware | 5:8965c2919afb | 94 | wait_us(1); |
rakware | 5:8965c2919afb | 95 | //led = !led; |
rakware | 4:2235d6d01ca5 | 96 | step = !step; |
rakware | 5:8965c2919afb | 97 | wait_us(1); |
rakware | 5:8965c2919afb | 98 | //led = !led; |
rakware | 4:2235d6d01ca5 | 99 | step = !step; |
rakware | 5:8965c2919afb | 100 | wait_us(1); |
rakware | 8:ccfbd168f077 | 101 | //wait((step_delay/1.024)/min_motor_pps/250); |
rakware | 3:20b077586e4e | 102 | gp++; |
rakware | 3:20b077586e4e | 103 | |
rakware | 3:20b077586e4e | 104 | } else { |
rakware | 3:20b077586e4e | 105 | |
rakware | 4:2235d6d01ca5 | 106 | step = dir = 0; |
rakware | 5:8965c2919afb | 107 | wait_us(1); |
rakware | 5:8965c2919afb | 108 | |
rakware | 6:c74fa5932b21 | 109 | i1.write(1.0f); //set minimum controller power while holding, keeps motor cool and still provides a nice holding torque, ~120ma |
rakware | 4:2235d6d01ca5 | 110 | |
rakware | 3:20b077586e4e | 111 | move = false; |
rakware | 0:c990fafbe0fc | 112 | |
rakware | 3:20b077586e4e | 113 | } |
rakware | 3:20b077586e4e | 114 | |
rakware | 3:20b077586e4e | 115 | } |
rakware | 3:20b077586e4e | 116 | |
rakware | 8:ccfbd168f077 | 117 | //} |
rakware | 3:20b077586e4e | 118 | |
rakware | 3:20b077586e4e | 119 | } |
rakware | 3:20b077586e4e | 120 | |
rakware | 3:20b077586e4e | 121 | |
rakware | 3:20b077586e4e | 122 | |
rakware | 3:20b077586e4e | 123 | //http://indilib.org/media/kunena/attachments/1/HighResSteppermotor107.pdf |
rakware | 2:c75920ffd4b1 | 124 | void read_serial() |
rakware | 0:c990fafbe0fc | 125 | { |
rakware | 8:ccfbd168f077 | 126 | while(true){ |
rakware | 8:ccfbd168f077 | 127 | if(pc.readable()) { |
rakware | 0:c990fafbe0fc | 128 | char c = pc.getc(); |
rakware | 0:c990fafbe0fc | 129 | |
rakware | 0:c990fafbe0fc | 130 | switch (c) { |
rakware | 0:c990fafbe0fc | 131 | case '#': |
rakware | 0:c990fafbe0fc | 132 | |
rakware | 0:c990fafbe0fc | 133 | switch (ml_in[0]) { |
rakware | 0:c990fafbe0fc | 134 | case 'C': //N/A Initiate a temperature conversion; the conversion process takes a maximum of 750 milliseconds. The value returned by the :GT# command will not be valid until the conversion process completes. |
rakware | 2:c75920ffd4b1 | 135 | break; //TODO |
rakware | 0:c990fafbe0fc | 136 | case 'F': |
rakware | 0:c990fafbe0fc | 137 | switch (ml_in[1]) { |
rakware | 0:c990fafbe0fc | 138 | case 'G': //N/A Go to the new position as set by the ":SNYYYY#" command. |
rakware | 4:2235d6d01ca5 | 139 | move = true; //runs motor(); |
rakware | 0:c990fafbe0fc | 140 | break; |
rakware | 0:c990fafbe0fc | 141 | case 'Q': //N/A Immediately stop any focus motor movement. |
rakware | 3:20b077586e4e | 142 | move = false; |
rakware | 0:c990fafbe0fc | 143 | break; |
rakware | 0:c990fafbe0fc | 144 | default: |
rakware | 0:c990fafbe0fc | 145 | break; |
rakware | 0:c990fafbe0fc | 146 | } |
rakware | 0:c990fafbe0fc | 147 | break; |
rakware | 0:c990fafbe0fc | 148 | |
rakware | 0:c990fafbe0fc | 149 | case 'G': |
rakware | 0:c990fafbe0fc | 150 | switch (ml_in[1]) { |
rakware | 0:c990fafbe0fc | 151 | case 'B': // Get the backlight value |
rakware | 0:c990fafbe0fc | 152 | pc.printf("00#"); |
rakware | 0:c990fafbe0fc | 153 | break; |
rakware | 0:c990fafbe0fc | 154 | case 'C': //XX# Returns the temperature coefficient where XX is a two-digit signed (2’s complement) hex number. |
rakware | 0:c990fafbe0fc | 155 | pc.printf("02#"); |
rakware | 0:c990fafbe0fc | 156 | break; |
rakware | 0:c990fafbe0fc | 157 | case 'D': //XX# Returns the current stepping delay where XX is a two-digit unsigned hex number. Valid values 02, 04, 08, 10, 20 -> stepping delay 250, 125, 63, 32, 16 pps |
rakware | 4:2235d6d01ca5 | 158 | pc.printf("%02X#", 512 / step_delay); //TODO? we sleep for step_delay*step_delay_multiplier microseconds between steps |
rakware | 0:c990fafbe0fc | 159 | break; |
rakware | 0:c990fafbe0fc | 160 | case 'H': //00# OR FF# Returns "FF#" if the focus motor is half-stepped otherwise return "00#" |
rakware | 4:2235d6d01ca5 | 161 | //pc.printf("00#"); //TODO |
rakware | 4:2235d6d01ca5 | 162 | pc.printf("%02X#", ms1 * 255); |
rakware | 0:c990fafbe0fc | 163 | break; |
rakware | 0:c990fafbe0fc | 164 | case 'I': //00# OR 01# Returns "00#" if the focus motor is not moving, otherwise return "01#" |
rakware | 8:ccfbd168f077 | 165 | pc.printf("%02X#", move); |
rakware | 0:c990fafbe0fc | 166 | break; |
rakware | 2:c75920ffd4b1 | 167 | case 'N': //YYYY# Returns the new position previously set by a ":SNYYYY#" command where YYYY is a four-digit unsigned hex number |
rakware | 2:c75920ffd4b1 | 168 | pc.printf("%04X#", gn); //TODO use this to move the motor |
rakware | 0:c990fafbe0fc | 169 | break; |
rakware | 0:c990fafbe0fc | 170 | case 'P': //YYYY# Returns the current position where YYYY is a four-digit unsigned hex number. |
rakware | 2:c75920ffd4b1 | 171 | pc.printf("%04X#", gp); //TODO update gp with actual motor data |
rakware | 0:c990fafbe0fc | 172 | break; |
rakware | 0:c990fafbe0fc | 173 | case 'T': //YYYY# Returns the current temperature where YYYY is a four-digit signed (2’s complement) hex number. |
rakware | 2:c75920ffd4b1 | 174 | pc.printf("%04X#", temperature * 2); //indi_moonlite_focuser returns the temp/2, dunno why, dont care |
rakware | 4:2235d6d01ca5 | 175 | //pc.printf("0019#"); //should be 25c but is 12.5c in indi_moonlite control panel |
rakware | 0:c990fafbe0fc | 176 | break; |
rakware | 0:c990fafbe0fc | 177 | case 'V': //DD# Get the version of the firmware as a two-digit decimal number where the first digit is the major version number, and the second digit is the minor version number. |
rakware | 0:c990fafbe0fc | 178 | pc.printf("01#"); |
rakware | 0:c990fafbe0fc | 179 | break; |
rakware | 0:c990fafbe0fc | 180 | default: |
rakware | 0:c990fafbe0fc | 181 | break; |
rakware | 0:c990fafbe0fc | 182 | } |
rakware | 0:c990fafbe0fc | 183 | break; |
rakware | 0:c990fafbe0fc | 184 | |
rakware | 0:c990fafbe0fc | 185 | case 'S': |
rakware | 0:c990fafbe0fc | 186 | switch(ml_in[1]) { |
rakware | 0:c990fafbe0fc | 187 | case 'C': //N/A Set the new temperature coefficient where XX is a two-digit, signed (2’s complement) hex number. |
rakware | 2:c75920ffd4b1 | 188 | break; //TODO |
rakware | 0:c990fafbe0fc | 189 | case 'D': //N/A Set the new stepping delay where XX is a two-digit, unsigned hex number. Valid values to send are 02, 04, 08, 10 and 20, which correspond to a stepping delay of 250, 125, 63, 32 and 16 steps per second respectively. |
rakware | 3:20b077586e4e | 190 | step_delay = 512 / strtol(ml_in + 2, NULL, 16); |
rakware | 8:ccfbd168f077 | 191 | m_speed.attach(&m_step, (step_delay/1.024)/min_motor_pps/250); |
rakware | 0:c990fafbe0fc | 192 | break; |
rakware | 0:c990fafbe0fc | 193 | |
rakware | 0:c990fafbe0fc | 194 | case 'F': //N/A Set full-step mode. |
rakware | 4:2235d6d01ca5 | 195 | ms1 = 0; |
rakware | 0:c990fafbe0fc | 196 | break; |
rakware | 0:c990fafbe0fc | 197 | |
rakware | 0:c990fafbe0fc | 198 | case 'H': //N/A Set half-step mode. |
rakware | 4:2235d6d01ca5 | 199 | ms1 = 1; |
rakware | 0:c990fafbe0fc | 200 | break; |
rakware | 0:c990fafbe0fc | 201 | |
rakware | 0:c990fafbe0fc | 202 | case 'N': //N/A Set the new position where YYYY is a four-digit unsigned hex number. |
rakware | 3:20b077586e4e | 203 | gn = strtol(ml_in + 2, NULL, 16); //read ml_in, discard 2 chars, convert to long, set gn |
rakware | 0:c990fafbe0fc | 204 | break; |
rakware | 0:c990fafbe0fc | 205 | |
rakware | 0:c990fafbe0fc | 206 | case 'P': //Set the current position where YYYY is a four-digit unsigned hex number. |
rakware | 2:c75920ffd4b1 | 207 | gp = strtol(ml_in + 2, NULL, 16); |
rakware | 0:c990fafbe0fc | 208 | break; |
rakware | 0:c990fafbe0fc | 209 | |
rakware | 0:c990fafbe0fc | 210 | default: |
rakware | 0:c990fafbe0fc | 211 | break; |
rakware | 0:c990fafbe0fc | 212 | } |
rakware | 0:c990fafbe0fc | 213 | break; |
rakware | 0:c990fafbe0fc | 214 | |
rakware | 0:c990fafbe0fc | 215 | case '+': //N/A Activate temperature compensation focusing. |
rakware | 0:c990fafbe0fc | 216 | break; //TODO |
rakware | 0:c990fafbe0fc | 217 | case '-': //N/A Disable temperature compensation focusing. |
rakware | 0:c990fafbe0fc | 218 | break; //TODO |
rakware | 0:c990fafbe0fc | 219 | |
rakware | 0:c990fafbe0fc | 220 | case 'P': |
rakware | 0:c990fafbe0fc | 221 | break; |
rakware | 0:c990fafbe0fc | 222 | |
rakware | 0:c990fafbe0fc | 223 | // case ':POXX#': //N/A Temperature calibration offset, XX is a two-digit signed hex number, in half degree increments. Example 1: :PO02# offset of +1°C Example 2: :POFB# offset of -2.5° |
rakware | 0:c990fafbe0fc | 224 | // break; //TODO |
rakware | 0:c990fafbe0fc | 225 | |
rakware | 0:c990fafbe0fc | 226 | default: |
rakware | 0:c990fafbe0fc | 227 | break; |
rakware | 0:c990fafbe0fc | 228 | } |
rakware | 0:c990fafbe0fc | 229 | break; |
rakware | 0:c990fafbe0fc | 230 | |
rakware | 0:c990fafbe0fc | 231 | case ':': |
rakware | 0:c990fafbe0fc | 232 | idx=0; |
rakware | 0:c990fafbe0fc | 233 | memset(ml_in, 0, 8); |
rakware | 0:c990fafbe0fc | 234 | break; |
rakware | 0:c990fafbe0fc | 235 | |
rakware | 0:c990fafbe0fc | 236 | default: |
rakware | 0:c990fafbe0fc | 237 | ml_in[idx++] = c; |
rakware | 0:c990fafbe0fc | 238 | idx %= 8; |
rakware | 0:c990fafbe0fc | 239 | break; |
rakware | 0:c990fafbe0fc | 240 | } |
rakware | 0:c990fafbe0fc | 241 | |
rakware | 0:c990fafbe0fc | 242 | |
rakware | 0:c990fafbe0fc | 243 | |
rakware | 0:c990fafbe0fc | 244 | } |
rakware | 8:ccfbd168f077 | 245 | }//while true |
rakware | 0:c990fafbe0fc | 246 | } |
rakware | 0:c990fafbe0fc | 247 | |
rakware | 0:c990fafbe0fc | 248 | |
rakware | 0:c990fafbe0fc | 249 | int main() |
rakware | 0:c990fafbe0fc | 250 | { |
rakware | 4:2235d6d01ca5 | 251 | mp6500(); |
rakware | 0:c990fafbe0fc | 252 | |
rakware | 8:ccfbd168f077 | 253 | //pc.attach(read_serial, Serial::RxIrq); |
rakware | 8:ccfbd168f077 | 254 | serial_thread.start(&read_serial); |
rakware | 4:2235d6d01ca5 | 255 | |
rakware | 8:ccfbd168f077 | 256 | //motor_thread.start(motor); |
rakware | 8:ccfbd168f077 | 257 | m_speed.attach(&m_step, (step_delay/1.024)/min_motor_pps/250); |
rakware | 8:ccfbd168f077 | 258 | |
rakware | 4:2235d6d01ca5 | 259 | |
rakware | 4:2235d6d01ca5 | 260 | while(true) { |
rakware | 8:ccfbd168f077 | 261 | Thread::wait(1); |
rakware | 4:2235d6d01ca5 | 262 | } |
rakware | 0:c990fafbe0fc | 263 | |
rakware | 0:c990fafbe0fc | 264 | } |