|
| 1 | +#include <Wire.h> |
| 2 | +#include "EncoderWrapper.h" |
| 3 | +#include "Battery.h" |
| 4 | +#include "DCMotor.h" |
| 5 | +#include "ServoMotor.h" |
| 6 | +#include "Common.h" |
| 7 | +#include "Events.h" |
| 8 | +#include "PID.h" |
| 9 | + |
| 10 | +#define Fix16 mn::MFixedPoint::FpF32<8> |
| 11 | + |
| 12 | +// compile me with target mkrmotorshield:samd:mkrmotorshield:bootloader=0kb,pinmap=complete,lto=disabled during development |
| 13 | +// compile me with target mkrmotorshield:samd:mkrmotorshield:bootloader=4kb,pinmap=complete,lto=enabled for release |
| 14 | + |
| 15 | +const char* FW_VERSION = "0.06"; |
| 16 | + |
| 17 | +DCMotor dcmotors[2] = { |
| 18 | + DCMotor(MOTOR_1_COUNTER, MOTOR_1_PIN_A, MOTOR_1_PIN_B), |
| 19 | + DCMotor(MOTOR_2_COUNTER, MOTOR_2_PIN_A, MOTOR_2_PIN_B), |
| 20 | +}; |
| 21 | + |
| 22 | +ServoMotor servos[4] = { |
| 23 | + ServoMotor(PWM_PIN_SERVO_1), |
| 24 | + ServoMotor(PWM_PIN_SERVO_2), |
| 25 | + ServoMotor(PWM_PIN_SERVO_3), |
| 26 | + ServoMotor(PWM_PIN_SERVO_4), |
| 27 | +}; |
| 28 | + |
| 29 | +EncoderWrapper encoders[2] = { |
| 30 | + EncoderWrapper(ENCODER_2_PIN_A, ENCODER_2_PIN_B, 1), |
| 31 | + EncoderWrapper(ENCODER_1_PIN_A, ENCODER_1_PIN_B, 0), |
| 32 | +}; |
| 33 | + |
| 34 | +PIDWrapper pid_control[2] = { |
| 35 | + PIDWrapper(encoders[0].position, encoders[0].velocity, &dcmotors[0], 0, 10, 100), //10ms period velo, 100ms period pos |
| 36 | + PIDWrapper(encoders[1].position, encoders[1].velocity, &dcmotors[1], 1, 10, 100), |
| 37 | +}; |
| 38 | + |
| 39 | +Battery battery(ADC_BATTERY); |
| 40 | + |
| 41 | +void led_on() { |
| 42 | + digitalWrite(LED_BUILTIN, HIGH); |
| 43 | +} |
| 44 | + |
| 45 | +void setup() { |
| 46 | + |
| 47 | + WDT->CTRL.reg &= ~WDT_CTRL_ENABLE; |
| 48 | + while (WDT->STATUS.reg & WDT_STATUS_SYNCBUSY); |
| 49 | + |
| 50 | + temp_init(); |
| 51 | + |
| 52 | + Wire.begin(I2C_ADDRESS); |
| 53 | + Wire.onRequest(requestEvent); |
| 54 | + Wire.onReceive(receiveEvent); |
| 55 | + pinMode(LED_BUILTIN, OUTPUT); |
| 56 | + pinMode(IRQ_PIN, OUTPUT); |
| 57 | + analogWriteResolution(8); |
| 58 | +} |
| 59 | + |
| 60 | +volatile uint8_t command = 0; |
| 61 | +volatile uint8_t target = 0; |
| 62 | +volatile uint8_t irq_status = 0; |
| 63 | +volatile unsigned long nextTimedEvent = 0; |
| 64 | +volatile unsigned long lastMessageReceived = 0; |
| 65 | + |
| 66 | +bool irq_enabled = true; |
| 67 | + |
| 68 | +void loop() { |
| 69 | + if (command == RESET || ((lastMessageReceived != 0) && (millis() - lastMessageReceived > 10000))) { |
| 70 | + reboot(); |
| 71 | + } |
| 72 | + if (command == PING) { |
| 73 | + lastMessageReceived = millis(); |
| 74 | + } |
| 75 | + executeTimedEvents(); |
| 76 | +} |
| 77 | + |
| 78 | +void receiveEvent(int howMany) { |
| 79 | + command = Wire.read(); |
| 80 | + if (Wire.available()) { |
| 81 | + target = Wire.read(); |
| 82 | + } else { |
| 83 | + return; |
| 84 | + } |
| 85 | + int value = 0; |
| 86 | + |
| 87 | + |
| 88 | + if (!Wire.available()) { |
| 89 | + return; |
| 90 | + } |
| 91 | + |
| 92 | + uint8_t buf[8]; |
| 93 | + int i = 0; |
| 94 | + while (Wire.available()) { |
| 95 | + buf[i++] = (uint8_t)Wire.read(); |
| 96 | + } |
| 97 | + |
| 98 | + // copies the bytes to int |
| 99 | + memcpy(&value, buf, sizeof(value)); |
| 100 | + |
| 101 | + switch (command) { |
| 102 | + case SET_PWM_DUTY_CYCLE_SERVO: |
| 103 | + servos[target].setDuty(value); |
| 104 | + break; |
| 105 | + case SET_PWM_FREQUENCY_SERVO: |
| 106 | + servos[target].setFrequency(value); |
| 107 | + break; |
| 108 | + case SET_PWM_DUTY_CYCLE_DC_MOTOR: |
| 109 | + ((PIDWrapper*)dcmotors[target].pid)->stop(); |
| 110 | + dcmotors[target].setDuty(value); |
| 111 | + break; |
| 112 | + case SET_PWM_FREQUENCY_DC_MOTOR: |
| 113 | + dcmotors[target].setFrequency(value); |
| 114 | + break; |
| 115 | + case RESET_COUNT_ENCODER: |
| 116 | + encoders[target].resetCounter(value); |
| 117 | + break; |
| 118 | + case SET_INTERRUPT_ON_COUNT_ENCODER: |
| 119 | + encoders[target].setIrqOnCount(value); |
| 120 | + break; |
| 121 | + case SET_INTERRUPT_ON_VELOCITY_ENCODER: |
| 122 | + encoders[target].setIrqOnVelocity(value); |
| 123 | + break; |
| 124 | + case SET_PID_GAIN_CL_MOTOR: |
| 125 | + { |
| 126 | + int16_t P16 = *((int16_t*)&buf[0]); |
| 127 | + int16_t I16 = *((int16_t*)&buf[2]); |
| 128 | + int16_t D16 = *((int16_t*)&buf[4]); |
| 129 | + Fix16 P = ((Fix16)P16) / short(1000); |
| 130 | + Fix16 I = ((Fix16)I16) / short(1000); |
| 131 | + Fix16 D = ((Fix16)D16) / short(1000); |
| 132 | + pid_control[target].setGains(P, I , D); |
| 133 | + break; |
| 134 | + } |
| 135 | + case RESET_PID_GAIN_CL_MOTOR: |
| 136 | + pid_control[target].resetGains(); |
| 137 | + break; |
| 138 | + case SET_CONTROL_MODE_CL_MOTOR: |
| 139 | + pid_control[target].setControlMode((cl_control)value); |
| 140 | + break; |
| 141 | + case SET_POSITION_SETPOINT_CL_MOTOR: |
| 142 | + pid_control[target].setSetpoint(TARGET_POSITION, Fix16(value * 1.0)); |
| 143 | + break; |
| 144 | + case SET_VELOCITY_SETPOINT_CL_MOTOR: |
| 145 | + pid_control[target].setSetpoint(TARGET_VELOCITY, Fix16(value * 1.0)); |
| 146 | + break; |
| 147 | + case SET_MAX_ACCELERATION_CL_MOTOR: { |
| 148 | + pid_control[target].setMaxAcceleration(Fix16(value * 1.0)); |
| 149 | + break; |
| 150 | + } |
| 151 | + case SET_MAX_VELOCITY_CL_MOTOR: |
| 152 | + pid_control[target].setMaxVelocity(Fix16(value * 1.0)); |
| 153 | + break; |
| 154 | + case SET_MIN_MAX_DUTY_CYCLE_CL_MOTOR: |
| 155 | + pid_control[target].setLimits(*((int16_t*)&buf[0]), *((int16_t*)&buf[2])); |
| 156 | + break; |
| 157 | + } |
| 158 | +} |
| 159 | + |
| 160 | +void requestEvent() { |
| 161 | + //deassert IRQ |
| 162 | + if (irq_enabled) { |
| 163 | + digitalWrite(IRQ_PIN, HIGH); |
| 164 | + } |
| 165 | + |
| 166 | + // Always reply with irq status |
| 167 | + Wire.write(irq_status); |
| 168 | + irq_status = 0; |
| 169 | + |
| 170 | + switch (command) { |
| 171 | + case GET_VERSION: |
| 172 | + getFWVersion(); |
| 173 | + break; |
| 174 | + case GET_RAW_COUNT_ENCODER: |
| 175 | + encoders[target].getRawCount(); |
| 176 | + break; |
| 177 | + case GET_OVERFLOW_UNDERFLOW_STATUS_ENCODER: |
| 178 | + encoders[target].getOverflowUnderflow(); |
| 179 | + break; |
| 180 | + case GET_COUNT_PER_SECOND_ENCODER: |
| 181 | + encoders[target].getCountPerSecond(); |
| 182 | + break; |
| 183 | + case GET_RAW_ADC_BATTERY: |
| 184 | + battery.getRaw(); |
| 185 | + break; |
| 186 | + case GET_CONVERTED_ADC_BATTERY: |
| 187 | + battery.getConverted(); |
| 188 | + break; |
| 189 | + case GET_FILTERED_ADC_BATTERY: |
| 190 | + battery.getFiltered(); |
| 191 | + break; |
| 192 | + case GET_INTERNAL_TEMP: |
| 193 | + getInternalTemperature(); |
| 194 | + break; |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +void requestAttention(int cause) { |
| 199 | + if (irq_enabled) { |
| 200 | + digitalWrite(IRQ_PIN, LOW); |
| 201 | + } |
| 202 | + irq_status |= (1 << cause); |
| 203 | +} |
| 204 | + |
| 205 | +void getFWVersion() { |
| 206 | + Wire.write(FW_VERSION); |
| 207 | +} |
| 208 | + |
| 209 | +void getInternalTemperature() { |
| 210 | + Wire.write(temp_raw_to_mdeg(temp_read_raw())); |
| 211 | +} |
| 212 | + |
| 213 | +void reboot() { |
| 214 | + NVIC_SystemReset(); |
| 215 | +} |
0 commit comments