diff --git a/python_motion/__pycache__/cobs_usb_serial.cpython-311.pyc b/python_motion/__pycache__/cobs_usb_serial.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ea2180ad5c1e908a82022d5565407cb9eeff271 Binary files /dev/null and b/python_motion/__pycache__/cobs_usb_serial.cpython-311.pyc differ diff --git a/python_motion/__pycache__/motor.cpython-311.pyc b/python_motion/__pycache__/motor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78819395db5c7a0421901aa096cb43df08c7b035 Binary files /dev/null and b/python_motion/__pycache__/motor.cpython-311.pyc differ diff --git a/python_motion/cobs_usb_serial.py b/python_motion/cobs_usb_serial.py new file mode 100644 index 0000000000000000000000000000000000000000..e98b83b5b08daa87e4d966a0bb4cfd2327c9630f --- /dev/null +++ b/python_motion/cobs_usb_serial.py @@ -0,0 +1,18 @@ +from cobs import cobs +import serial + + +class CobsUsbSerial: + def __init__(self, port, baudrate=115200): + self.port = port + self.baudrate = baudrate + self.ser = serial.Serial(port, baudrate=baudrate, timeout=1) + + def write(self, data: bytes): + data_enc = cobs.encode(data) + b"\x00" + self.ser.write(data_enc) + + def read(self): + data_enc = self.ser.read_until(b"\x00") + data = cobs.decode(data_enc[:-1]) + return data diff --git a/python_motion/motion.py b/python_motion/motion.py new file mode 100644 index 0000000000000000000000000000000000000000..f393d5d3cfa708481549393957e6fcffee380b87 --- /dev/null +++ b/python_motion/motion.py @@ -0,0 +1,92 @@ +from motor import Motor +import random +import time + +home_rate = 100 +home_accel = 2000 +home_backoff_time = 0.5 + +go_rate = 150 +go_accel = 2000 + +use_current = 0.2 + +y_motor = Motor("COM25") +print("y_motor: (1): ", y_motor.get_id()) + +x_bottom_motor = Motor("COM7") +print("x_bottom: (2): ", x_bottom_motor.get_id()) +x_top_motor = Motor("COM28") +print("x_top: (3): ", x_top_motor.get_id()) + + +# steps / unit, +y_motor.set_steps_per_unit(200 / 40) +x_bottom_motor.set_steps_per_unit(-200 /40) +x_top_motor.set_steps_per_unit(200 / 40) + +# power up +y_motor.set_current(use_current) +x_bottom_motor.set_current(use_current) +x_top_motor.set_current(use_current) + + +# home Y .... +# if we're on the switch, backoff: +if y_motor.get_states()['limit'] > 0: + y_motor.set_target_velocity(home_rate, home_accel) + time.sleep(home_backoff_time) + y_motor.set_target_velocity(0, home_accel) + time.sleep(home_backoff_time) + +# let's home it, +y_motor.set_target_velocity(-home_rate, home_accel) + +# then check-wait on states, +while True: + states = y_motor.get_states() + if states['limit'] > 0: + break; + +y_motor.set_target_velocity(0, home_accel) + + +# home X ... +if x_top_motor.get_states()['limit'] > 0: + x_bottom_motor.set_target_velocity(home_rate, home_accel) + x_top_motor.set_target_velocity(home_rate, home_accel) + time.sleep(home_backoff_time) + x_bottom_motor.set_target_velocity(0, home_accel) + x_top_motor.set_target_velocity(0, home_accel) + time.sleep(home_backoff_time) + + +x_bottom_motor.set_target_velocity(-home_rate, home_accel) +x_top_motor.set_target_velocity(-home_rate, home_accel) + +while True: + states = x_top_motor.get_states() + if states['limit'] > 0: + break; + +x_bottom_motor.set_target_velocity(0, home_accel) +x_top_motor.set_target_velocity(0, home_accel) +time.sleep(home_backoff_time) + +# set zeroes, +x_bottom_motor.set_position(0) +x_top_motor.set_position(0) +y_motor.set_position(0) + + +# goto points +def goto(x, y, vel, accel): + x_bottom_motor.set_target_position_no_wait(x, vel, accel) + x_top_motor.set_target_position_no_wait(x, vel, accel) + y_motor.set_target_position_no_wait(y, vel, accel) + # # ... wait while not at point: + # while True: + # x_bot_state = x_bottom_motor.get_states() + + +goto(200, 100, go_rate, go_accel) \ No newline at end of file diff --git a/python_motion/motor.py b/python_motion/motor.py new file mode 100644 index 0000000000000000000000000000000000000000..57f348f05029061e09ba8fdd74e697a59984de3a --- /dev/null +++ b/python_motion/motor.py @@ -0,0 +1,85 @@ +from cobs_usb_serial import CobsUsbSerial +import struct + + +MSG_GET_ID = 7 +MSG_ECHO_TEST = 11 +MSG_SET_TARG_VEL = 21 +MSG_SET_TARG_POS = 22 +MSG_SET_POSITION = 23 +MSG_SET_CURRENT = 24 +MSG_GET_STATES = 25 +MSG_ACK = 31 +MSG_NACK = 32 + + +class Motor: + def __init__(self, port: str): + self.cobs = CobsUsbSerial(port) + self.spu = 200 + + + def get_id(self): + msg = struct.pack('=B', MSG_GET_ID) + self.cobs.write(msg) + ack, device_id = struct.unpack('=BB', self.cobs.read()) + return device_id + + + def set_steps_per_unit(self, spu): + self.spu = spu + + + def test(self) -> None: + test_bytes = bytes([MSG_ECHO_TEST, 14, 16]) + print("testing w/ an echo-packet: ", [byte for byte in test_bytes]) + self.cobs.write(test_bytes) + reply = self.cobs.read() + print("test echo returns: ", [byte for byte in reply]) + + + def set_target_velocity(self, velocity: float, accel: float): + msg = struct.pack('=Bff', MSG_SET_TARG_VEL, velocity * self.spu, accel * self.spu) + self.cobs.write(msg) + return struct.unpack('=B', self.cobs.read()) + + + def set_target_position_no_wait(self, position: float, velocity: float, accel: float): + msg = struct.pack('=Bfff', MSG_SET_TARG_POS, position * self.spu, velocity * self.spu, accel * self.spu) + self.cobs.write(msg) + return + + + def set_target_position(self, position: float, velocity: float, accel: float): + self.set_target_position_no_wait(position, velocity, accel) + return struct.unpack('=B', self.cobs.read()) + + + def set_position(self, position: float): + msg = struct.pack('=Bf', MSG_SET_POSITION, position * self.spu) + self.cobs.write(msg) + return struct.unpack('=B', self.cobs.read()) + + + def set_current(self, current: float): + msg = struct.pack('=Bf', MSG_SET_CURRENT, current) + self.cobs.write(msg) + return struct.unpack('=B', self.cobs.read()) + + + def get_states(self): + self.cobs.write(bytes([MSG_GET_STATES])) + reply = self.cobs.read() + # print("states returns: ", [byte for byte in reply]) + + ack, position, velocity, acceleration, limit = struct.unpack('=BfffB', reply) + + return { + 'ack': ack, + 'position': position / self.spu, + 'velocity': velocity / self.spu, + 'acceleration': acceleration / self.spu, + 'limit': limit + } + + \ No newline at end of file diff --git a/python_motion/serial_list.py b/python_motion/serial_list.py new file mode 100644 index 0000000000000000000000000000000000000000..5f25377227f77c79dc2db925a16f5a5a280f412b --- /dev/null +++ b/python_motion/serial_list.py @@ -0,0 +1,20 @@ +import serial.tools.list_ports + +def list_serial_ports(): + ports = serial.tools.list_ports.comports() + for port in ports: + print(f"Port: {port.device}") + print(f" - Description: {port.description}") + if port.serial_number: + print(f" - Serial Number: {port.serial_number}") + if port.manufacturer: + print(f" - Manufacturer: {port.manufacturer}") + if port.product: + print(f" - Product: {port.product}") + if port.vid is not None: + print(f" - VID: {port.vid:04X}") + if port.pid is not None: + print(f" - PID: {port.pid:04X}") + print() + +list_serial_ports() diff --git a/simple-stepper/.vscode/arduino.json b/simple-stepper/.vscode/arduino.json new file mode 100644 index 0000000000000000000000000000000000000000..a8e46da7bb42e76975165be17f7b7aacfba4b512 --- /dev/null +++ b/simple-stepper/.vscode/arduino.json @@ -0,0 +1,6 @@ +{ + "port": "COM7", + "configuration": "flash=2097152_0,freq=200,opt=Small,rtti=Disabled,stackprotect=Disabled,exceptions=Disabled,dbgport=Disabled,dbglvl=None,usbstack=picosdk,ipbtstack=ipv4only,uploadmethod=default", + "board": "rp2040:rp2040:seeed_xiao_rp2040", + "sketch": "simple-stepper.ino" +} \ No newline at end of file diff --git a/simple-stepper/.vscode/c_cpp_properties.json b/simple-stepper/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..17cdc59d4fa403e1d1d0d9c7993a114b7bd618aa --- /dev/null +++ b/simple-stepper/.vscode/c_cpp_properties.json @@ -0,0 +1,524 @@ +{ + "version": 4, + "configurations": [ + { + "name": "Arduino", + "compilerPath": "C:\\Users\\jaker\\AppData\\Local\\Arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\bin\\arm-none-eabi-g++", + "compilerArgs": [ + "-I", + "-Werror=return-type", + "-Wno-psabi", + "-march=armv6-m", + "-mcpu=cortex-m0plus", + "-mthumb", + "-ffunction-sections", + "-fdata-sections", + "-fno-exceptions" + ], + "intelliSenseMode": "gcc-x64", + "includePath": [ + "C:\\Users\\jaker\\AppData\\Local\\Arduino15\\packages\\rp2040\\hardware\\rp2040\\3.5.0\\include", + "C:\\Users\\jaker\\AppData\\Local\\Arduino15\\packages\\rp2040\\hardware\\rp2040\\3.5.0\\cores\\rp2040", + "C:\\Users\\jaker\\AppData\\Local\\Arduino15\\packages\\rp2040\\hardware\\rp2040\\3.5.0\\variants\\seeed_xiao_rp2040", + "c:\\users\\jaker\\appdata\\local\\arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\arm-none-eabi\\include\\c++\\12.3.0", + "c:\\users\\jaker\\appdata\\local\\arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\arm-none-eabi\\include\\c++\\12.3.0\\arm-none-eabi\\thumb", + "c:\\users\\jaker\\appdata\\local\\arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\arm-none-eabi\\include\\c++\\12.3.0\\backward", + "c:\\users\\jaker\\appdata\\local\\arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\lib\\gcc\\arm-none-eabi\\12.3.0\\include", + "c:\\users\\jaker\\appdata\\local\\arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\lib\\gcc\\arm-none-eabi\\12.3.0\\include-fixed", + "c:\\users\\jaker\\appdata\\local\\arduino15\\packages\\rp2040\\tools\\pqt-gcc\\2.1.0-a-d3d2e6b\\arm-none-eabi\\include" + ], + "forcedInclude": [ + "C:\\Users\\jaker\\AppData\\Local\\Arduino15\\packages\\rp2040\\hardware\\rp2040\\3.5.0\\cores\\rp2040\\Arduino.h" + ], + "cStandard": "c11", + "cppStandard": "c++17", + "defines": [ + "CFG_TUSB_MCU=OPT_MCU_RP2040", + "USBD_PID=0x000a", + "USBD_VID=0x2e8a", + "USBD_MAX_POWER_MA=250", + "USB_MANUFACTURER=\"Seeed\"", + "USB_PRODUCT=\"XIAO RP2040\"", + "PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1", + "CYW43_LWIP=1", + "LWIP_IPV6=0", + "LWIP_IPV4=1", + "LWIP_IGMP=1", + "LWIP_CHECKSUM_CTRL_PER_NETIF=1", + "ARDUINO_VARIANT=\"seeed_xiao_rp2040\"", + "TARGET_RP2040", + "PICO_FLASH_SIZE_BYTES=2097152", + "ARM_MATH_CM0_FAMILY", + "ARM_MATH_CM0_PLUS", + "F_CPU=200000000L", + "ARDUINO=10607", + "ARDUINO_SEEED_XIAO_RP2040", + "BOARD_NAME=\"SEEED_XIAO_RP2040\"", + "ARDUINO_ARCH_RP2040", + "WIFICC=CYW43_COUNTRY_WORLDWIDE", + "__DBL_MIN_EXP__=(-1021)", + "__HQ_FBIT__=15", + "__cpp_attributes=200809L", + "__cpp_nontype_template_parameter_auto=201606L", + "__UINT_LEAST16_MAX__=0xffff", + "__ARM_SIZEOF_WCHAR_T=4", + "__ATOMIC_ACQUIRE=2", + "__SFRACT_IBIT__=0", + "__FLT_MIN__=1.1754943508222875e-38F", + "__GCC_IEC_559_COMPLEX=0", + "__cpp_aggregate_nsdmi=201304L", + "__UFRACT_MAX__=0XFFFFP-16UR", + "__UINT_LEAST8_TYPE__=unsigned char", + "__DQ_FBIT__=63", + "__INTMAX_C(c)=c ## LL", + "__ULFRACT_FBIT__=32", + "__CHAR_BIT__=8", + "__USQ_IBIT__=0", + "__UINT8_MAX__=0xff", + "__ACCUM_FBIT__=15", + "__WINT_MAX__=0xffffffffU", + "__FLT32_MIN_EXP__=(-125)", + "__cpp_static_assert=201411L", + "__USFRACT_FBIT__=8", + "__ORDER_LITTLE_ENDIAN__=1234", + "__SIZE_MAX__=0xffffffffU", + "__WCHAR_MAX__=0xffffffffU", + "__LACCUM_IBIT__=32", + "__DBL_DENORM_MIN__=double(4.9406564584124654e-324L)", + "__GCC_ATOMIC_CHAR_LOCK_FREE=1", + "__GCC_IEC_559=0", + "__FLT32X_DECIMAL_DIG__=17", + "__FLT_EVAL_METHOD__=0", + "__TQ_IBIT__=0", + "__cpp_binary_literals=201304L", + "__LLACCUM_MAX__=0X7FFFFFFFFFFFFFFFP-31LLK", + "__FLT64_DECIMAL_DIG__=17", + "__cpp_noexcept_function_type=201510L", + "__GCC_ATOMIC_CHAR32_T_LOCK_FREE=1", + "__cpp_variadic_templates=200704L", + "__UINT_FAST64_MAX__=0xffffffffffffffffULL", + "__SIG_ATOMIC_TYPE__=int", + "__DBL_MIN_10_EXP__=(-307)", + "__FINITE_MATH_ONLY__=0", + "__ARMEL__=1", + "__cpp_variable_templates=201304L", + "__FLT32X_MAX_EXP__=1024", + "__LFRACT_IBIT__=0", + "__GNUC_PATCHLEVEL__=0", + "__FLT32_HAS_DENORM__=1", + "__LFRACT_MAX__=0X7FFFFFFFP-31LR", + "__USA_FBIT__=16", + "__UINT_FAST8_MAX__=0xffffffffU", + "__cpp_rvalue_reference=200610L", + "__cpp_nested_namespace_definitions=201411L", + "__INT8_C(c)=c", + "__INT_LEAST8_WIDTH__=8", + "__cpp_variadic_using=201611L", + "__UINT_LEAST64_MAX__=0xffffffffffffffffULL", + "__INT_LEAST8_MAX__=0x7f", + "__SA_FBIT__=15", + "__cpp_capture_star_this=201603L", + "__SHRT_MAX__=0x7fff", + "__LDBL_MAX__=1.7976931348623157e+308L", + "__FRACT_MAX__=0X7FFFP-15R", + "__cpp_if_constexpr=201606L", + "__LDBL_IS_IEC_60559__=2", + "__UFRACT_FBIT__=16", + "__UFRACT_MIN__=0.0UR", + "__UINT_LEAST8_MAX__=0xff", + "__GCC_ATOMIC_BOOL_LOCK_FREE=1", + "__UINTMAX_TYPE__=long long unsigned int", + "__LLFRACT_EPSILON__=0x1P-63LLR", + "__FLT_EVAL_METHOD_TS_18661_3__=0", + "__CHAR_UNSIGNED__=1", + "__UINT32_MAX__=0xffffffffUL", + "__GXX_EXPERIMENTAL_CXX0X__=1", + "__ULFRACT_MAX__=0XFFFFFFFFP-32ULR", + "__TA_IBIT__=64", + "__LDBL_MAX_EXP__=1024", + "__WINT_MIN__=0U", + "__FLT32X_IS_IEC_60559__=2", + "__INT_LEAST16_WIDTH__=16", + "__ULLFRACT_MIN__=0.0ULLR", + "__SCHAR_MAX__=0x7f", + "__WCHAR_MIN__=0U", + "__INT64_C(c)=c ## LL", + "__GCC_ATOMIC_POINTER_LOCK_FREE=1", + "__LLACCUM_MIN__=(-0X1P31LLK-0X1P31LLK)", + "__SIZEOF_INT__=4", + "__FLT32X_MANT_DIG__=53", + "__GCC_ATOMIC_CHAR16_T_LOCK_FREE=1", + "__USACCUM_IBIT__=8", + "__cpp_aligned_new=201606L", + "__FLT32_MAX_10_EXP__=38", + "__STDC_HOSTED__=1", + "__LFRACT_MIN__=(-0.5LR-0.5LR)", + "__HA_IBIT__=8", + "__cpp_decltype_auto=201304L", + "__DBL_DIG__=15", + "__FLT32_DIG__=6", + "__FLT_EPSILON__=1.1920928955078125e-7F", + "__APCS_32__=1", + "__GXX_WEAK__=1", + "__SHRT_WIDTH__=16", + "__FLT32_IS_IEC_60559__=2", + "__USFRACT_IBIT__=0", + "__LDBL_MIN__=2.2250738585072014e-308L", + "__DBL_IS_IEC_60559__=2", + "__FRACT_MIN__=(-0.5R-0.5R)", + "__cpp_threadsafe_static_init=200806L", + "__DA_IBIT__=32", + "__ARM_SIZEOF_MINIMAL_ENUM=1", + "__FLT32X_HAS_INFINITY__=1", + "__INT32_MAX__=0x7fffffffL", + "__UQQ_FBIT__=8", + "__INT_WIDTH__=32", + "__SIZEOF_LONG__=4", + "__UACCUM_MAX__=0XFFFFFFFFP-16UK", + "__UINT16_C(c)=c", + "__DECIMAL_DIG__=17", + "__LFRACT_EPSILON__=0x1P-31LR", + "__FLT64_EPSILON__=2.2204460492503131e-16F64", + "__ULFRACT_MIN__=0.0ULR", + "__INT16_MAX__=0x7fff", + "__FLT64_MIN_EXP__=(-1021)", + "__LDBL_HAS_QUIET_NAN__=1", + "__ULACCUM_IBIT__=32", + "__FLT64_MANT_DIG__=53", + "__UACCUM_EPSILON__=0x1P-16UK", + "__GNUC__=12", + "__ULLACCUM_MAX__=0XFFFFFFFFFFFFFFFFP-32ULLK", + "__GXX_RTTI=1", + "__HQ_IBIT__=0", + "__FLT_HAS_DENORM__=1", + "__SIZEOF_LONG_DOUBLE__=8", + "__SA_IBIT__=16", + "__BIGGEST_ALIGNMENT__=8", + "__STDC_UTF_16__=1", + "__FLT64_MAX_10_EXP__=308", + "__GNUC_STDC_INLINE__=1", + "__DQ_IBIT__=0", + "__cpp_delegating_constructors=200604L", + "__FLT32_HAS_INFINITY__=1", + "__DBL_MAX__=double(1.7976931348623157e+308L)", + "__ULFRACT_IBIT__=0", + "__cpp_raw_strings=200710L", + "__INT_FAST32_MAX__=0x7fffffff", + "__DBL_HAS_INFINITY__=1", + "__cpp_deduction_guides=201703L", + "__HAVE_SPECULATION_SAFE_VALUE=1", + "__cpp_fold_expressions=201603L", + "__ACCUM_IBIT__=16", + "__THUMB_INTERWORK__=1", + "__INTPTR_WIDTH__=32", + "__UINT_LEAST32_MAX__=0xffffffffUL", + "__ULLACCUM_IBIT__=32", + "__LACCUM_MAX__=0X7FFFFFFFFFFFFFFFP-31LK", + "__FLT32X_HAS_DENORM__=1", + "__INT_FAST16_TYPE__=int", + "__LDBL_HAS_DENORM__=1", + "__cplusplus=201703L", + "__cpp_ref_qualifiers=200710L", + "__INT_LEAST32_MAX__=0x7fffffffL", + "__ARM_PCS=1", + "__ACCUM_MAX__=0X7FFFFFFFP-15K", + "__DEPRECATED=1", + "__ARM_ARCH_6M__=1", + "__cpp_rvalue_references=200610L", + "__DBL_MAX_EXP__=1024", + "__USACCUM_EPSILON__=0x1P-8UHK", + "__WCHAR_WIDTH__=32", + "__FLT32_MAX__=3.4028234663852886e+38F32", + "__GCC_ATOMIC_LONG_LOCK_FREE=1", + "__SFRACT_MAX__=0X7FP-7HR", + "__FRACT_IBIT__=0", + "__PTRDIFF_MAX__=0x7fffffff", + "__UACCUM_MIN__=0.0UK", + "__UACCUM_IBIT__=16", + "__FLT32_HAS_QUIET_NAN__=1", + "__GNUG__=12", + "__LONG_LONG_MAX__=0x7fffffffffffffffLL", + "__ULACCUM_MAX__=0XFFFFFFFFFFFFFFFFP-32ULK", + "__cpp_nsdmi=200809L", + "__SIZEOF_WINT_T__=4", + "__LONG_LONG_WIDTH__=64", + "__cpp_initializer_lists=200806L", + "__FLT32_MAX_EXP__=128", + "__ULLACCUM_MIN__=0.0ULLK", + "__cpp_hex_float=201603L", + "__GXX_ABI_VERSION=1017", + "__UTA_FBIT__=64", + "__FLT_MIN_EXP__=(-125)", + "__UFRACT_IBIT__=0", + "__cpp_enumerator_attributes=201411L", + "__cpp_lambdas=200907L", + "__INT_FAST64_TYPE__=long long int", + "__FLT64_DENORM_MIN__=4.9406564584124654e-324F64", + "__DBL_MIN__=double(2.2250738585072014e-308L)", + "__SIZEOF_POINTER__=4", + "__DBL_HAS_QUIET_NAN__=1", + "__FLT32X_EPSILON__=2.2204460492503131e-16F32x", + "__LACCUM_MIN__=(-0X1P31LK-0X1P31LK)", + "__FRACT_FBIT__=15", + "__ULLACCUM_FBIT__=32", + "__GXX_TYPEINFO_EQUALITY_INLINE=0", + "__FLT64_MIN_10_EXP__=(-307)", + "__ULLFRACT_EPSILON__=0x1P-64ULLR", + "__USES_INITFINI__=1", + "__REGISTER_PREFIX__", + "__UINT16_MAX__=0xffff", + "__ACCUM_MIN__=(-0X1P15K-0X1P15K)", + "__SQ_IBIT__=0", + "__FLT32_MIN__=1.1754943508222875e-38F32", + "__UINT8_TYPE__=unsigned char", + "__UHA_FBIT__=8", + "__FLT_DIG__=6", + "__NO_INLINE__=1", + "__SFRACT_MIN__=(-0.5HR-0.5HR)", + "__UTQ_FBIT__=128", + "__DEC_EVAL_METHOD__=2", + "__FLT_MANT_DIG__=24", + "__LDBL_DECIMAL_DIG__=17", + "__VERSION__=\"12.3.0\"", + "__UINT64_C(c)=c ## ULL", + "__ULLFRACT_FBIT__=64", + "__cpp_unicode_characters=201411L", + "__SOFTFP__=1", + "__FRACT_EPSILON__=0x1P-15R", + "__ULACCUM_MIN__=0.0ULK", + "__UDA_FBIT__=32", + "__LLACCUM_EPSILON__=0x1P-31LLK", + "__GCC_ATOMIC_INT_LOCK_FREE=1", + "__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__", + "__USFRACT_MIN__=0.0UHR", + "__FLT32_MANT_DIG__=24", + "__cpp_aggregate_bases=201603L", + "__UQQ_IBIT__=0", + "__USFRACT_MAX__=0XFFP-8UHR", + "__SCHAR_WIDTH__=8", + "__INT32_C(c)=c ## L", + "__ORDER_PDP_ENDIAN__=3412", + "__UHQ_FBIT__=16", + "__LLACCUM_FBIT__=31", + "__INT_FAST32_TYPE__=int", + "__UINT_LEAST16_TYPE__=short unsigned int", + "__DBL_HAS_DENORM__=1", + "__cpp_rtti=199711L", + "__SIZE_TYPE__=unsigned int", + "__UINT64_MAX__=0xffffffffffffffffULL", + "__FLT_IS_IEC_60559__=2", + "__UDQ_FBIT__=64", + "__GNUC_WIDE_EXECUTION_CHARSET_NAME=\"UTF-32LE\"", + "__INT8_TYPE__=signed char", + "__thumb__=1", + "__cpp_digit_separators=201309L", + "__ELF__=1", + "__SACCUM_EPSILON__=0x1P-7HK", + "__ULFRACT_EPSILON__=0x1P-32ULR", + "__LLFRACT_FBIT__=63", + "__FLT_RADIX__=2", + "__INT_LEAST16_TYPE__=short int", + "__ARM_ARCH_PROFILE=77", + "__LDBL_EPSILON__=2.2204460492503131e-16L", + "__UINTMAX_C(c)=c ## ULL", + "__SACCUM_MAX__=0X7FFFP-7HK", + "__FLT32X_MIN__=2.2250738585072014e-308F32x", + "__SIG_ATOMIC_MAX__=0x7fffffff", + "__UACCUM_FBIT__=16", + "__GCC_ATOMIC_WCHAR_T_LOCK_FREE=1", + "__USER_LABEL_PREFIX__", + "__VFP_FP__=1", + "__SIZEOF_PTRDIFF_T__=4", + "__LACCUM_EPSILON__=0x1P-31LK", + "__LDBL_DIG__=15", + "__FLT64_IS_IEC_60559__=2", + "__FLT32X_MIN_EXP__=(-1021)", + "__INT_FAST16_MAX__=0x7fffffff", + "__GCC_CONSTRUCTIVE_SIZE=64", + "__FLT64_DIG__=15", + "__UINT_FAST32_MAX__=0xffffffffU", + "__UINT_LEAST64_TYPE__=long long unsigned int", + "__SFRACT_EPSILON__=0x1P-7HR", + "__FLT_HAS_QUIET_NAN__=1", + "__FLT_MAX_10_EXP__=38", + "__LONG_MAX__=0x7fffffffL", + "__SIZEOF_SIZE_T__=4", + "__FLT_HAS_INFINITY__=1", + "__GNUC_EXECUTION_CHARSET_NAME=\"UTF-8\"", + "__cpp_unicode_literals=200710L", + "__UINT_FAST16_TYPE__=unsigned int", + "__INT_FAST32_WIDTH__=32", + "__CHAR16_TYPE__=short unsigned int", + "__PRAGMA_REDEFINE_EXTNAME=1", + "__SIZE_WIDTH__=32", + "__INT_LEAST16_MAX__=0x7fff", + "__INT64_MAX__=0x7fffffffffffffffLL", + "__SACCUM_FBIT__=7", + "__FLT32_DENORM_MIN__=1.4012984643248171e-45F32", + "__SIG_ATOMIC_WIDTH__=32", + "__INT_LEAST64_TYPE__=long long int", + "__INT16_TYPE__=short int", + "__INT_LEAST8_TYPE__=signed char", + "__cpp_structured_bindings=201606L", + "__SQ_FBIT__=31", + "__ARM_ARCH_ISA_THUMB=1", + "__INT_FAST8_MAX__=0x7fffffff", + "__ARM_ARCH=6", + "__INTPTR_MAX__=0x7fffffff", + "__cpp_sized_deallocation=201309L", + "__cpp_guaranteed_copy_elision=201606L", + "__QQ_FBIT__=7", + "__UTA_IBIT__=64", + "__FLT64_HAS_QUIET_NAN__=1", + "__FLT32_MIN_10_EXP__=(-37)", + "__EXCEPTIONS=1", + "__PTRDIFF_WIDTH__=32", + "__LDBL_MANT_DIG__=53", + "__SFRACT_FBIT__=7", + "__cpp_range_based_for=201603L", + "__SACCUM_MIN__=(-0X1P7HK-0X1P7HK)", + "__FLT64_HAS_INFINITY__=1", + "__STDCPP_DEFAULT_NEW_ALIGNMENT__=8", + "__SIG_ATOMIC_MIN__=(-__SIG_ATOMIC_MAX__ - 1)", + "__cpp_nontype_template_args=201411L", + "__cpp_return_type_deduction=201304L", + "__INTPTR_TYPE__=int", + "__UINT16_TYPE__=short unsigned int", + "__WCHAR_TYPE__=unsigned int", + "__SIZEOF_FLOAT__=4", + "__THUMBEL__=1", + "__TQ_FBIT__=127", + "__USQ_FBIT__=32", + "__UINTPTR_MAX__=0xffffffffU", + "__INT_FAST64_WIDTH__=64", + "__cpp_decltype=200707L", + "__FLT32_DECIMAL_DIG__=9", + "__INT_FAST64_MAX__=0x7fffffffffffffffLL", + "__GCC_ATOMIC_TEST_AND_SET_TRUEVAL=1", + "__FLT_NORM_MAX__=3.4028234663852886e+38F", + "__UINT_FAST64_TYPE__=long long unsigned int", + "__cpp_inline_variables=201606L", + "__INT_MAX__=0x7fffffff", + "__LACCUM_FBIT__=31", + "__USACCUM_MIN__=0.0UHK", + "__UHA_IBIT__=8", + "__INT64_TYPE__=long long int", + "__FLT_MAX_EXP__=128", + "__UTQ_IBIT__=0", + "__DBL_MANT_DIG__=53", + "__cpp_inheriting_constructors=201511L", + "__INT_LEAST64_MAX__=0x7fffffffffffffffLL", + "__WINT_TYPE__=unsigned int", + "__UINT_LEAST32_TYPE__=long unsigned int", + "__SIZEOF_SHORT__=2", + "__ULLFRACT_IBIT__=0", + "__FLT32_NORM_MAX__=3.4028234663852886e+38F32", + "__LDBL_MIN_EXP__=(-1021)", + "__arm__=1", + "__FLT64_MAX__=1.7976931348623157e+308F64", + "__UDA_IBIT__=32", + "__WINT_WIDTH__=32", + "__cpp_template_auto=201606L", + "__INT_LEAST64_WIDTH__=64", + "__FLT32X_MAX_10_EXP__=308", + "__LFRACT_FBIT__=31", + "__WCHAR_UNSIGNED__=1", + "__LDBL_MAX_10_EXP__=308", + "__ATOMIC_RELAXED=0", + "__DBL_EPSILON__=double(2.2204460492503131e-16L)", + "__UINT8_C(c)=c", + "__FLT64_MAX_EXP__=1024", + "__INT_LEAST32_TYPE__=long int", + "__SIZEOF_WCHAR_T__=4", + "__LLFRACT_MAX__=0X7FFFFFFFFFFFFFFFP-63LLR", + "__FLT64_NORM_MAX__=1.7976931348623157e+308F64", + "__INTMAX_MAX__=0x7fffffffffffffffLL", + "__INT_FAST8_TYPE__=int", + "__cpp_namespace_attributes=201411L", + "__ULLACCUM_EPSILON__=0x1P-32ULLK", + "__USACCUM_MAX__=0XFFFFP-8UHK", + "__LDBL_HAS_INFINITY__=1", + "__UHQ_IBIT__=0", + "__LLACCUM_IBIT__=32", + "__FLT64_HAS_DENORM__=1", + "__FLT32_EPSILON__=1.1920928955078125e-7F32", + "__DBL_DECIMAL_DIG__=17", + "__STDC_UTF_32__=1", + "__INT_FAST8_WIDTH__=32", + "__FLT32X_MAX__=1.7976931348623157e+308F32x", + "__TA_FBIT__=63", + "__DBL_NORM_MAX__=double(1.7976931348623157e+308L)", + "__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__", + "__GCC_DESTRUCTIVE_SIZE=64", + "__UDQ_IBIT__=0", + "__INTMAX_WIDTH__=64", + "__ORDER_BIG_ENDIAN__=4321", + "__cpp_runtime_arrays=198712L", + "__UINT64_TYPE__=long long unsigned int", + "__ACCUM_EPSILON__=0x1P-15K", + "__UINT32_C(c)=c ## UL", + "__cpp_alias_templates=200704L", + "__FLT_DENORM_MIN__=1.4012984643248171e-45F", + "__LLFRACT_IBIT__=0", + "__INT8_MAX__=0x7f", + "__LONG_WIDTH__=32", + "__UINT_FAST32_TYPE__=unsigned int", + "__FLT32X_NORM_MAX__=1.7976931348623157e+308F32x", + "__CHAR32_TYPE__=long unsigned int", + "__FLT_MAX__=3.4028234663852886e+38F", + "__cpp_constexpr=201603L", + "__USACCUM_FBIT__=8", + "__INT32_TYPE__=long int", + "__SIZEOF_DOUBLE__=8", + "__cpp_exceptions=199711L", + "__FLT_MIN_10_EXP__=(-37)", + "__UFRACT_EPSILON__=0x1P-16UR", + "__FLT64_MIN__=2.2250738585072014e-308F64", + "__INT_LEAST32_WIDTH__=32", + "__INTMAX_TYPE__=long long int", + "__FLT32X_HAS_QUIET_NAN__=1", + "__ATOMIC_CONSUME=1", + "__GNUC_MINOR__=3", + "__INT_FAST16_WIDTH__=32", + "__UINTMAX_MAX__=0xffffffffffffffffULL", + "__FLT32X_DENORM_MIN__=4.9406564584124654e-324F32x", + "__HA_FBIT__=7", + "__cpp_template_template_args=201611L", + "__DBL_MAX_10_EXP__=308", + "__LDBL_DENORM_MIN__=4.9406564584124654e-324L", + "__INT16_C(c)=c", + "__STDC__=1", + "__FLT32X_DIG__=15", + "__PTRDIFF_TYPE__=int", + "__LLFRACT_MIN__=(-0.5LLR-0.5LLR)", + "__ATOMIC_SEQ_CST=5", + "__DA_FBIT__=31", + "__UINT32_TYPE__=long unsigned int", + "__FLT32X_MIN_10_EXP__=(-307)", + "__UINTPTR_TYPE__=unsigned int", + "__USA_IBIT__=16", + "__ARM_EABI__=1", + "__LDBL_MIN_10_EXP__=(-307)", + "__cpp_generic_lambdas=201304L", + "__SIZEOF_LONG_LONG__=8", + "__ULACCUM_EPSILON__=0x1P-32ULK", + "__cpp_user_defined_literals=200809L", + "__SACCUM_IBIT__=8", + "__GCC_ATOMIC_LLONG_LOCK_FREE=1", + "__FLT_DECIMAL_DIG__=9", + "__UINT_FAST16_MAX__=0xffffffffU", + "__LDBL_NORM_MAX__=1.7976931348623157e+308L", + "__GCC_ATOMIC_SHORT_LOCK_FREE=1", + "__ULLFRACT_MAX__=0XFFFFFFFFFFFFFFFFP-64ULLR", + "__UINT_FAST8_TYPE__=unsigned int", + "__USFRACT_EPSILON__=0x1P-8UHR", + "__ULACCUM_FBIT__=32", + "__QQ_IBIT__=0", + "__cpp_init_captures=201304L", + "__ATOMIC_ACQ_REL=4", + "__ATOMIC_RELEASE=3", + "USBCON" + ] + } + ] +} \ No newline at end of file diff --git a/simple-stepper/COBSUSBSerial.cpp b/simple-stepper/COBSUSBSerial.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03939cc7b407f9f9d5e891a19bf39b513886e3ff --- /dev/null +++ b/simple-stepper/COBSUSBSerial.cpp @@ -0,0 +1,89 @@ +// link ! +// TODO: pls use nanocobs, for encode- and decode-in-place, to save big (!) memory +// on new link layer... to fit into D11s... + +#include "COBSUSBSerial.h" +#include "cobs.h" + + +#if defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2040) +COBSUSBSerial::COBSUSBSerial(SerialUSB* _usbcdc){ + usbcdc = _usbcdc; +} +#else +COBSUSBSerial::COBSUSBSerial(Serial_* _usbcdc){ + usbcdc = _usbcdc; +} +#endif + +void COBSUSBSerial::begin(void){ + usbcdc->begin(9600); +} + +void COBSUSBSerial::loop(void){ + // check RX side: + // while data & not-full, + while(usbcdc->available() && rxBufferLen == 0){ + rxBuffer[rxBufferWp ++] = usbcdc->read(); + if(rxBuffer[rxBufferWp - 1] == 0){ + // decoding in place should always work: COBS doesn't revisit bytes + // encoding in place would be a different trick, and would require the use of + // nanocobs from this lad: https://github.com/charlesnicholson/nanocobs + size_t len = cobsDecode(rxBuffer, 255, rxBuffer); + // now we are with-packet, set length and reset write pointer + // len includes the trailing 0, rm that... + rxBufferLen = len - 1; + rxBufferWp = 0; + } + } + + // check tx side, + while(txBufferLen && usbcdc->availableForWrite()){ + // ship a byte, + usbcdc->write(txBuffer[txBufferRp ++]); + // if done, mark empty + if(txBufferRp >= txBufferLen){ + txBufferLen = 0; + txBufferRp = 0; + } + } +} + +size_t COBSUSBSerial::getPacket(uint8_t* dest){ + if(rxBufferLen > 0){ + memcpy(dest, rxBuffer, rxBufferLen); + size_t len = rxBufferLen; + rxBufferLen = 0; + return len; + } else { + return 0; + } +} + +boolean COBSUSBSerial::clearToRead(void){ + return (rxBufferLen > 0); +} + +void COBSUSBSerial::send(uint8_t* packet, size_t len){ + // ship it! blind! + size_t encodedLen = cobsEncode(packet, len, txBuffer); + // stuff 0 byte, + txBuffer[encodedLen] = 0; + txBufferLen = encodedLen + 1; + txBufferRp = 0; +} + +boolean COBSUSBSerial::clearToSend(void){ + // we're CTS if we have nothing in the outbuffer, + return (txBufferLen == 0); +} + +// we should do some... work with this, i.e. +// keepalives, to detect if other-end is open or not... +boolean COBSUSBSerial::isOpen(void){ + if(usbcdc){ + return true; + } else { + return false; + } +} \ No newline at end of file diff --git a/simple-stepper/COBSUSBSerial.h b/simple-stepper/COBSUSBSerial.h new file mode 100644 index 0000000000000000000000000000000000000000..4c87ab9653062e5e00d983256ac2fb61b41ae575 --- /dev/null +++ b/simple-stepper/COBSUSBSerial.h @@ -0,0 +1,37 @@ +// example cobs-encoded usb-serial link + +#include <Arduino.h> + +class COBSUSBSerial { + public: + #if defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2040) + COBSUSBSerial(SerialUSB* _usbcdc); + #else + COBSUSBSerial(Serial_* _usbcdc); + #endif + void begin(void); + void loop(void); + // check & read, + boolean clearToRead(void); + size_t getPacket(uint8_t* dest); + // clear ahead? + boolean clearToSend(void); + // open at all? + boolean isOpen(void); + // transmit a packet of this length + void send(uint8_t* packet, size_t len); + private: + #if defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2040) + SerialUSB* usbcdc = nullptr; + #else + Serial_* usbcdc = nullptr; + #endif + // buffer, write pointer, length, + uint8_t rxBuffer[255]; + uint8_t rxBufferWp = 0; + uint8_t rxBufferLen = 0; + // ibid, + uint8_t txBuffer[255]; + uint8_t txBufferRp = 0; + uint8_t txBufferLen = 0; +}; \ No newline at end of file diff --git a/simple-stepper/cobs.cpp b/simple-stepper/cobs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f243ad4a2618360ac2acd8ee80a4f48d023513b --- /dev/null +++ b/simple-stepper/cobs.cpp @@ -0,0 +1,72 @@ +/* +utils/cobs.cpp + +Jake Read at the Center for Bits and Atoms +(c) Massachusetts Institute of Technology 2019 + +This work may be reproduced, modified, distributed, performed, and +displayed for any purpose, but must acknowledge the osap project. +Copyright is retained and must be preserved. The work is provided as is; +no warranty is provided, and users accept all liability. +*/ + +#include "cobs.h" +// str8 crib from +// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing + +/** COBS encode data to buffer + @param data Pointer to input data to encode + @param length Number of bytes to encode + @param buffer Pointer to encoded output buffer + @return Encoded buffer length in bytes + @note doesn't write stop delimiter +*/ + +size_t cobsEncode(const void *data, size_t length, uint8_t *buffer){ + + uint8_t *encode = buffer; // Encoded byte pointer + uint8_t *codep = encode++; // Output code pointer + uint8_t code = 1; // Code value + + for (const uint8_t *byte = (const uint8_t *)data; length--; ++byte){ + if (*byte) // Byte not zero, write it + *encode++ = *byte, ++code; + + if (!*byte || code == 0xff){ // Input is zero or block completed, restart + *codep = code, code = 1, codep = encode; + if (!*byte || length) + ++encode; + } + } + *codep = code; // Write final code value + return encode - buffer; +} + +/** COBS decode data from buffer + @param buffer Pointer to encoded input bytes + @param length Number of bytes to decode + @param data Pointer to decoded output data + @return Number of bytes successfully decoded + @note Stops decoding if delimiter byte is found +*/ + +size_t cobsDecode(const uint8_t *buffer, size_t length, void *data){ + + const uint8_t *byte = buffer; // Encoded input byte pointer + uint8_t *decode = (uint8_t *)data; // Decoded output byte pointer + + for (uint8_t code = 0xff, block = 0; byte < buffer + length; --block){ + if (block) // Decode block byte + *decode++ = *byte++; + else + { + if (code != 0xff) // Encoded zero, write it + *decode++ = 0; + block = code = *byte++; // Next block length + if (code == 0x00) // Delimiter code found + break; + } + } + + return decode - (uint8_t *)data; +} diff --git a/simple-stepper/cobs.h b/simple-stepper/cobs.h new file mode 100644 index 0000000000000000000000000000000000000000..b47070ca26d021f113da680a6835df65712d4007 --- /dev/null +++ b/simple-stepper/cobs.h @@ -0,0 +1,24 @@ +/* +utils/cobs.h + +consistent overhead byte stuffing implementation + +Jake Read at the Center for Bits and Atoms +(c) Massachusetts Institute of Technology 2019 + +This work may be reproduced, modified, distributed, performed, and +displayed for any purpose, but must acknowledge the osap project. +Copyright is retained and must be preserved. The work is provided as is; +no warranty is provided, and users accept all liability. +*/ + +#ifndef UTIL_COBS_H_ +#define UTIL_COBS_H_ + +#include <Arduino.h> + +size_t cobsEncode(const void *data, size_t length, uint8_t *buffer); + +size_t cobsDecode(const uint8_t *buffer, size_t length, void *data); + +#endif diff --git a/simple-stepper/fixedPointUtes.cpp b/simple-stepper/fixedPointUtes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af6568d3a8338ac20fc51f62622fa55c00464617 --- /dev/null +++ b/simple-stepper/fixedPointUtes.cpp @@ -0,0 +1,80 @@ +#include "fixedPointUtes.h" + +// ---------------------------------------------- Fixed Point Maths + +// FP 16.16 puts 65k ticks in front and in behind, +// for i.e. max rate of 32k 'units' (it's signed) +// which correlates to 9830 RPM for a 200-full-step stepper +const int32_t fp_scale = 16; +const float fp_float_max = 32768.0F; +const float fp_float_min = -32768.0F; +const int32_t fp_int_max = 32768; +const int32_t fp_int_min = -32768; +const int64_t fp_32b_max = 2147483648; +const int64_t fp_32b_min = -2147483648; + +// hmmm https://www.youtube.com/watch?v=S12qx1DwjVk& at ~ 18:00 +float fp_fixed32ToFloat(fpint32_t fixed){ + return ((float)fixed / (float)(1 << fp_scale)); +} + +float fp_fixed64ToFloat(fpint64_t fixed){ + return ((float)fixed / (float)(1 << fp_scale)); +} + +// actually this is unclear to me... https://www.youtube.com/watch?v=S12qx1DwjVk& at 16:57 +fpint32_t fp_floatToFixed32(float flt){ + if(flt > fp_float_max) flt = fp_float_max; + if(flt < fp_float_min) flt = fp_float_min; + return (flt * (float)(1 << fp_scale)); +} + +fpint64_t fp_floatToFixed64(float flt){ + return (flt * (float)(1 << fp_scale)); +} + +int32_t fp_fixed32ToInt32(fpint32_t fixed){ + return (fixed >> fp_scale); +} + +fpint32_t fp_int32ToFixed32(int32_t inty){ + if(inty > fp_int_max) inty = fp_int_max; + if(inty < fp_int_min) inty = fp_int_min; + return (inty << fp_scale); +} + +fpint32_t fp_mult32x32(fpint32_t a, fpint32_t b){ + // the result of this mult can be > our max possible 32b-wide fixedp, + int64_t res = ((int64_t)(a) * (int64_t)(b)) >> fp_scale; + // so we guard against that, since it is cast back to 32b on exit, + if(res > fp_32b_max) res = fp_32b_max; + if(res < fp_32b_min) res = fp_32b_min; + return res; +} + +// we could instead do mult w/ some fancy shifting, for speed (no 64b at all) +// but it also makes for tricky overflow / etc; I'm not going to get into this yet +// https://www.youtube.com/watch?v=npQF28g6s_k& 7:40 +// fp_int32_t fp_mult(fpint32_t a, fpint32_t b){ +// return ((a >> 6) * (b >> 6)) >> 4; +// } + +fpint32_t fp_div32x32(fpint32_t num, fpint32_t denum){ + return ((int64_t)(num) << fp_scale) / denum; +} + +fpint64_t fp_mult32x32_64(fpint32_t a, fpint32_t b){ + return ((fpint64_t)(a) * (fpint64_t)(b)) >> fp_scale; +} + +fpint64_t fp_div64x64(fpint64_t num, fpint64_t denum){ + return (num << 16) / denum; +} + +// // big-div, +// fpint64_t fp_calcStopDistance(fpint32_t _vel, fpint32_t _maxAccel){ +// // return 0; +// int64_t _velSq = ((int64_t)(_vel) * (int64_t)(_vel)) >> fp_scale; +// int64_t _accelTwo = ((int64_t)(_maxAccel) * (int64_t)(fp_int32ToFixed32(2))) >> fp_scale; +// return (_velSq << fp_scale) / _accelTwo; +// } \ No newline at end of file diff --git a/simple-stepper/fixedPointUtes.h b/simple-stepper/fixedPointUtes.h new file mode 100644 index 0000000000000000000000000000000000000000..20c0c6cac09edd403a2a105ccf02afe61b31ef59 --- /dev/null +++ b/simple-stepper/fixedPointUtes.h @@ -0,0 +1,36 @@ +#ifndef FIXEDPOINT_UTES_H_ +#define FIXEDPOINT_UTES_H_ + +#include <Arduino.h> + +// ---------------------------------------------- structs and interfaes + +// we get explicit about fixed point +typedef int32_t fpint32_t; +typedef int64_t fpint64_t; + +// ---------------------------------------------- fixedp conversions + +float fp_fixed32ToFloat(fpint32_t fixed); +float fp_fixed64ToFloat(fpint64_t fixed); + +fpint32_t fp_floatToFixed32(float flt); +fpint64_t fp_floatToFixed64(float flt); + +int32_t fp_fixed32ToInt32(fpint32_t fixed); + +fpint32_t fp_int32ToFixed32(int32_t inty); + +// ---------------------------------------------- fixedp maths + +fpint32_t fp_mult32x32(fpint32_t a, fpint32_t b); + +fpint32_t fp_div32x32(fpint32_t num, fpint32_t denum); + +// ---------------------------------------------- overflow fixedp maths + +fpint64_t fp_mult32x32_64(fpint32_t a, fpint32_t b); + +fpint64_t fp_div64x64(fpint64_t num, fpint64_t denum); + +#endif \ No newline at end of file diff --git a/simple-stepper/lutgen.js b/simple-stepper/lutgen.js new file mode 100644 index 0000000000000000000000000000000000000000..07a6d1499e9af17bb5b3f8981f89b679044dadec --- /dev/null +++ b/simple-stepper/lutgen.js @@ -0,0 +1,60 @@ +import fs from 'fs'; +import process from 'process'; + +// Function to generate the sinusoid values +function generateSinusoid(length, amplitude) { + let values = []; + for (let i = 0; i < length; i++) { + let angle = (Math.PI * i) / (length - 1); + let value = Math.round(amplitude * Math.sin(angle)); + values.push(value); + } + return values; +} + +// Main function to create the lookup table +function createLookupTable(length, amplitude) { + const values = generateSinusoid(length, amplitude); + let lutString = `#ifndef STEPPER_LUT_H_\n#define STEPPER_LUT_H_\n\n` + lutString += `#include <Arduino.h>\n\n`; + lutString += `#define LUT_LENGTH ${length} \n`; + lutString += `#define PWM_PERIOD ${amplitude}\n\n`; + lutString += `const uint16_t LUT[LUT_LENGTH] = {\n`; + // do 'em row by row + let i = 0; + while (i < values.length) { + lutString += ` `; + for (let j = 0; j < 16; j++) { + lutString += `${values[i]}, `; + i++; + if (i >= values.length) break; + } + lutString += `\n`; + } + // lutString += values.join(',') + ',\n'; + lutString += '};\n\n'; + lutString += `#endif\n` + return lutString; +} + +// Read command-line arguments +const length = parseInt(process.argv[2]); +const amplitude = parseInt(process.argv[3]); + +// Validate arguments +if (isNaN(length) || isNaN(amplitude)) { + console.error('Usage: node script.js <length> <amplitude>'); + process.exit(1); +} + +// Generate the lookup table string +const lutString = createLookupTable(length, amplitude); + +// Write to file +fs.writeFile('stepperLUT.h', lutString, (err) => { + if (err) { + console.error('Error writing to file:', err); + } else { + console.log('Lookup table written to stepperLUT.h'); + } +}); diff --git a/simple-stepper/motionStateMachine.cpp b/simple-stepper/motionStateMachine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c66f4fafcc8ba0dbeee6353d375ed685479d1674 --- /dev/null +++ b/simple-stepper/motionStateMachine.cpp @@ -0,0 +1,215 @@ +#include "motionStateMachine.h" +#include "fixedPointUtes.h" +#include "stepperDriver.h" + +// overlapping with the limit pin ! +#define PIN_DEBUG 26 + +#define ALARM_DT_NUM 1 +#define ALARM_DT_IRQ TIMER_IRQ_1 + +// _delT is re-calculated when we init w/ a new microsecondsPerIntegration +fpint32_t _delT = 0; +uint32_t _delT_us = 0; + +// core states (units are full steps) +volatile uint8_t _mode = MOTION_MODE_VEL; // operative _mode +volatile fpint64_t _pos = 0; // current position (big 64) +volatile fpint32_t _vel = 0; // current velocity +volatile fpint32_t _accel = 0; // current acceleration + +// init-once values we'll use in the integrator +volatile fpint32_t _delta = 0; +volatile fpint64_t _posTarget = 0; // for position control, +volatile fpint64_t _dist = 0; // for position control, +volatile fpint64_t _stopDistance = 0; // for position control, + +// and settings +fpint32_t _maxAccel = 0; // maximum acceleration +fpint32_t _maxVelocity = 0; + +// nasty ! +fpint32_t _velEpsilon = 0; + +void motion_init(uint32_t microsecondsPerIntegration){ + // here's our delta-tee for each integration step + _delT = fp_floatToFixed32((float)(microsecondsPerIntegration) / 1000000.0F); + // and (for resetting our timer) the _delta directly in us + _delT_us = microsecondsPerIntegration; + + // setup the hardware timer + hw_set_bits(&timer_hw->inte, 1u << ALARM_DT_NUM); + irq_set_exclusive_handler(ALARM_DT_IRQ, alarm_dt_handler); + irq_set_enabled(ALARM_DT_IRQ, true); + timer_hw->alarm[ALARM_DT_NUM] = (uint32_t) (timer_hw->timerawl + _delT_us); + + // (optionally) use a debug pin to perf test + // pinMode(PIN_DEBUG, OUTPUT); + _velEpsilon = fp_floatToFixed32(1.0F); +} + +void alarm_dt_handler(void){ + // setup next call right away + hw_clear_bits(&timer_hw->intr, 1u << ALARM_DT_NUM); + timer_hw->alarm[ALARM_DT_NUM] = (uint32_t) (timer_hw->timerawl + _delT_us); + // do the motion system integration, + // sio_hw->gpio_set = (uint32_t)(1 << PIN_DEBUG); + motion_integrate(); + // sio_hw->gpio_clr = (uint32_t)(1 << PIN_DEBUG); +} + +// ------------------------------------ integrator codes + +fpint64_t motion_calc_stopping_distance(fpint32_t vel, fpint32_t accel){ + // our num / denum, + fpint64_t velSqrd = fp_mult32x32_64(vel, vel); + fpint64_t twoAccel = fp_mult32x32_64(fp_int32ToFixed32(2), accel); + // now we div that out, + return fp_div64x64(velSqrd, twoAccel); +} + +void motion_calc_mode_velocity(void){ + // go fast, or go slo; + if(_vel < _maxVelocity){ + _accel = _maxAccel; + } else if (_vel > _maxVelocity){ + _accel = -_maxAccel; + } + + // using our chosen accel, integrate velocity from previous: + _vel += fp_mult32x32(_accel, _delT); + + // and check against targets + // TODO: hack-ey velocity-at-target thing (1st if here) + // should dead-reckon step intervals, checking a delta, + // but requires that we check which direction we are going (towards velocity) + if( _maxVelocity < _velEpsilon && _maxVelocity > -_velEpsilon && // if we are near-zero target velocity, + _vel < _velEpsilon && _vel > -_velEpsilon // and we are also ... near that velocity, + ){ + _accel = 0; + _vel = 0; + } else if(_vel > 0 && _maxVelocity > 0 && _vel > _maxVelocity){ + _accel = 0; + _vel = _maxVelocity; + } else if(_vel < 0 && _maxVelocity < 0 && _vel < _maxVelocity){ + _accel = 0; + _vel = _maxVelocity; + } +} + +void motion_calc_mode_position(void){ + // figure whence we would need to start stopping, and our current dist + _stopDistance = motion_calc_stopping_distance(_vel, _maxAccel); + _dist = _posTarget - _pos; + + // check if we're about to make it... bonk if so, + // units are steps, so epsilon is tiny ! + if(abs(_dist - _delta) < fp_floatToFixed32(0.001F)){ + _vel = 0; + _accel = 0; + return; + } + + // now we do a buncha cheques + if(_stopDistance >= abs(_dist)){ // we're going to overshoot, + if(_vel <= 0){ // when -ve vel, + _accel = _maxAccel; // do +ve accel + } else { // when +ve vel, + _accel = -_maxAccel; // do -ve accel + } + } else { // we're not overshooting, + if(_dist > 0){ // if delta is positive, + _accel = _maxAccel; // go forwards, + } else { // if it's negative + _accel = -_maxAccel; // go backwards... + } + } + + // using our chosen accel, integrate velocity from previous: + _vel += fp_mult32x32(_accel, _delT); + + // cap our _vel based on maximum rates: + if(_vel >= _maxVelocity){ + _accel = 0; + _vel = _maxVelocity; + } else if (_vel <= -_maxVelocity){ + _accel = 0; + _vel = -_maxVelocity; + } +} + +void motion_integrate(void){ + // set our _accel based on modal requests, + switch(_mode){ + case MOTION_MODE_POS: + motion_calc_mode_position(); + break; + case MOTION_MODE_VEL: + motion_calc_mode_velocity(); + break; + } + + // grab a delta and integrate, + _delta = fp_mult32x32(_vel, _delT); + _pos += _delta; + + // position is base 16, we can just shift our way to relative electrical phase + // 0-2048 (11 bits) per electrical phase, is + // 0-512 (9 bits) per step, + // 0b XXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXX + // 0b XX.XXXXXXXXX + // FS.MicroStep + uint16_t phaseAngle = (_pos >> 7) & 0b11111111111; + stepper_point(phaseAngle); +} + +// ------------------------------------ end integrator + +void motion_setVelocityTarget(float target, float maxAccel){ + noInterrupts(); + _maxAccel = fp_floatToFixed32(abs(maxAccel)); + _maxVelocity = fp_floatToFixed32(target); + _mode = MOTION_MODE_VEL; + interrupts(); +} + +void motion_setPosition(float pos){ + noInterrupts(); + _pos = fp_floatToFixed64(pos); + interrupts(); +} + +void motion_getCurrentStates(motionState_t* statePtr){ + noInterrupts(); + statePtr->pos = fp_fixed64ToFloat(_pos); + statePtr->vel = fp_fixed32ToFloat(_vel); + statePtr->accel = fp_fixed32ToFloat(_accel); + interrupts(); +} + +void motion_setPositionTarget(float target, float maxVel, float maxAccel){ + noInterrupts(); + _posTarget = fp_floatToFixed64(target); + _maxVelocity = fp_floatToFixed32(abs(maxVel)); + _maxAccel = fp_floatToFixed32(abs(maxAccel)); + _mode = MOTION_MODE_POS; + interrupts(); +} + +// void motion_debug(void){ +// // ... we could / should snapshot, if this is chunky ? +// noInterrupts(); +// Serial.println(String(millis()) +// // + "\t_delT: \t" + String(fp_fixed32ToFloat(_delT), 6) +// + "\tm: " + String(_mode) +// + "\tptrg: " + String(fp_fixed64ToFloat(_posTarget), 1) +// + "\tvtrg: " + String(fp_fixed64ToFloat(_maxVelocity), 1) +// + "\tpos: " + String(fp_fixed64ToFloat(_pos), 1) +// + "\tdst: " + String(fp_fixed64ToFloat(_dist), 1) +// + "\tstp: " + String(fp_fixed64ToFloat(_stopDistance), 1) +// + "\tacc: " + String(fp_fixed32ToFloat(_accel), 1) +// + "\tvel: " + String(fp_fixed32ToFloat(_vel), 1) +// // + "\tvtrg: \t" + String(fp_fixed32ToFloat(_maxVelocity), 4) +// ); +// interrupts(); +// } diff --git a/simple-stepper/motionStateMachine.h b/simple-stepper/motionStateMachine.h new file mode 100644 index 0000000000000000000000000000000000000000..678abf78815698e08d855211b7701267ce29a522 --- /dev/null +++ b/simple-stepper/motionStateMachine.h @@ -0,0 +1,28 @@ +#ifndef MOTION_STATE_MACHINE_H_ +#define MOTION_STATE_MACHINE_H_ + +#include <Arduino.h> +#include <hardware/timer.h> +#include <hardware/irq.h> + +#define MOTION_MODE_POS 0 +#define MOTION_MODE_VEL 1 + +typedef struct motionState_t { + float pos; + float vel; + float accel; +} motionState_t; + +void motion_init(uint32_t microsecondsPerIntegration); + +void motion_integrate(void); +void alarm_dt_handler(void); + +void motion_setPositionTarget(float target, float maxVel, float maxAccel); +void motion_setVelocityTarget(float target, float maxAccel); +void motion_setPosition(float pos); + +void motion_getCurrentStates(motionState_t* statePtr); + +#endif diff --git a/simple-stepper/serializationUtes.cpp b/simple-stepper/serializationUtes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d40cd2193b351ac1d15e27e3cba674648737dcbf --- /dev/null +++ b/simple-stepper/serializationUtes.cpp @@ -0,0 +1,14 @@ +#include "serializationUtes.h" + +float ts_readFloat32(unsigned char* buf, uint16_t* ptr){ + chunk_float32 chunk = { .bytes = { buf[(*ptr)], buf[(*ptr) + 1], buf[(*ptr) + 2], buf[(*ptr) + 3] } }; + (*ptr) += 4; + return chunk.f; +} + +void ts_writeFloat32(float val, volatile unsigned char* buf, uint16_t* ptr){ + chunk_float32 chunk; + chunk.f = val; + buf[(*ptr)] = chunk.bytes[0]; buf[(*ptr) + 1] = chunk.bytes[1]; buf[(*ptr) + 2] = chunk.bytes[2]; buf[(*ptr) + 3] = chunk.bytes[3]; + (*ptr) += 4; +} \ No newline at end of file diff --git a/simple-stepper/serializationUtes.h b/simple-stepper/serializationUtes.h new file mode 100644 index 0000000000000000000000000000000000000000..5549f09e32458c55014cfd8b9880cf028e965383 --- /dev/null +++ b/simple-stepper/serializationUtes.h @@ -0,0 +1,15 @@ +#ifndef SERIALIZATION_UTES_H_ +#define SERIALIZATION_UTES_H_ + +#include <Arduino.h> + +union chunk_float32 { + uint8_t bytes[4]; + float f; +}; + +float ts_readFloat32(unsigned char* buf, uint16_t* ptr); + +void ts_writeFloat32(float val, volatile unsigned char* buf, uint16_t* ptr); + +#endif \ No newline at end of file diff --git a/simple-stepper/simple-stepper.ino b/simple-stepper/simple-stepper.ino new file mode 100644 index 0000000000000000000000000000000000000000..613158e0acbc3f146c48631807317175795bca8f --- /dev/null +++ b/simple-stepper/simple-stepper.ino @@ -0,0 +1,154 @@ +#include "COBSUSBSerial.h" +#include "serializationUtes.h" +#include "motionStateMachine.h" +#include "stepperDriver.h" + +// no-transport-layer stepper motor +// using the RP2040 at 200MHz +// using https://modular-things.github.io/modular-things/things/stepper-hbridge-xiao/ + +#define PIN_LIMIT 26 + +#define MSG_GET_ID 7 +#define MSG_ECHO_TEST 11 +#define MSG_SET_TARG_VEL 21 +#define MSG_SET_TARG_POS 22 +#define MSG_SET_POSITION 23 +#define MSG_SET_CURRENT 24 +#define MSG_GET_STATES 25 +#define MSG_ACK 31 +#define MSG_NACK 32 + +// y_motor: 1, x_bottom_motor: 2, x_top_motor: 3 +#define MOTOR_ID 3 + +COBSUSBSerial cobs(&Serial); + + +void setTargetVelocity(uint8_t* data, size_t len){ + uint16_t wptr = 0; + float targ = ts_readFloat32(data, &wptr); + float maxAccel = ts_readFloat32(data, &wptr); + motion_setVelocityTarget(targ, maxAccel); +} + + +void setTargetPosition(uint8_t* data, size_t len){ + uint16_t wptr = 0; + float targ = ts_readFloat32(data, &wptr); + float maxVel = ts_readFloat32(data, &wptr); + float maxAccel = ts_readFloat32(data, &wptr); + motion_setPositionTarget(targ, maxVel, maxAccel); +} + + +void setPosition(uint8_t* data, size_t len){ + // should do maxAccel, maxVel, and (optionally) setPosition + // upstream should've though of this, so, + uint16_t rptr = 0; + float pos = ts_readFloat32(data, &rptr); + motion_setPosition(pos); +} + + +void setCurrent(uint8_t* data, size_t len){ + // it's just <cscale> for the time being, + uint16_t rptr = 0; + float cscale = ts_readFloat32(data, &rptr); + // we get that as a floating p, 0-1, + // driver wants integers 0-1024: + uint32_t amp = cscale * 1024; + stepper_setAmplitude(amp); +} + + +boolean lastButtonState = false; + +size_t getStates(uint8_t* data, size_t len, uint8_t* reply){ + motionState_t state; + motion_getCurrentStates(&state); + uint16_t wptr = 0; + // in-fill current posn, velocity, and acceleration + ts_writeFloat32(state.pos, reply, &wptr); + ts_writeFloat32(state.vel, reply, &wptr); + ts_writeFloat32(state.accel, reply, &wptr); + // and limit state, + reply[wptr ++] = (lastButtonState ? 1 : 0); + // return the data length + return wptr; +} + + +void setup() { + // startup the stepper hardware + stepper_init(); + // setup motion, pick an integration interval (us) + motion_init(64); + // and our limit pin, is wired (to spec) + // to a normally-closed switch, from SIG to GND, + // meaning that when the switch is "clicked" - it will open, + // and the pullup will win, we will have logic high + pinMode(PIN_LIMIT, INPUT_PULLUP); + // and our comms + cobs.begin(); +} + + +uint32_t debounceDelay = 1; +uint32_t lastButtonCheck = 0; + +motionState_t states; + +uint8_t msg[256]; +uint8_t reply[256]; + +void loop() { + // run comms + cobs.loop(); + // and check for paquiats: condition is if we can + // get a packet, and tx the reply + if(cobs.clearToRead() && cobs.clearToSend()){ + size_t len = cobs.getPacket(msg); + // start a reply, + size_t wptr = 0; + reply[wptr ++] = MSG_ACK; + // switch on grams, + switch(msg[0]){ + case MSG_GET_ID: + reply[wptr ++] = MOTOR_ID; + break; + case MSG_ECHO_TEST: + memcpy(reply, msg, len); + wptr = len; + break; + case MSG_SET_TARG_VEL: + setTargetVelocity(msg + 1, len - 1); + break; + case MSG_SET_TARG_POS: + setTargetPosition(msg + 1, len - 1); + break; + case MSG_SET_POSITION: + setPosition(msg + 1, len - 1); + break; + case MSG_SET_CURRENT: + setCurrent(msg + 1, len - 1); + break; + case MSG_GET_STATES: + wptr += getStates(msg + 1, len - 1, reply + 1); + break; + default: + reply[0] = MSG_NACK; + break; + } + // send the reply, + cobs.send(reply, wptr); + } + // debounce and set button states, + if(lastButtonCheck + debounceDelay < millis()){ + lastButtonCheck = millis(); + boolean newState = digitalRead(PIN_LIMIT); + if(newState != lastButtonState){ + lastButtonState = newState; + } + } +} diff --git a/simple-stepper/stepperDriver.cpp b/simple-stepper/stepperDriver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4dfdff3ddea8defb89355514d73505e4ea8e7344 --- /dev/null +++ b/simple-stepper/stepperDriver.cpp @@ -0,0 +1,143 @@ +/* +stepperDriver.cpp + +stepper code for two A4950s or TB67... w/ VREF via TC -> RC Filters +for the RP2040 XIAO ! + +Jake Read at the Center for Bits and Atoms +(c) Massachusetts Institute of Technology 2022 + +This work may be reproduced, modified, distributed, performed, and +displayed for any purpose, but must acknowledge the squidworks and ponyo +projects. Copyright is retained and must be preserved. The work is provided as +is; no warranty is provided, and users accept all liability. +*/ + +#include "stepperDriver.h" +#include "stepperLUT.h" + +#define AIN1_PIN 6 // on D4 +#define AIN2_PIN 7 // on D5 +#define BIN1_PIN 28 // on D2 +#define BIN2_PIN 4 // on D9 +#define APWM_PIN 27 // on D1 +#define BPWM_PIN 29 // on D3 + +// macros to set h-bridge dir pins + +#define AIN1_HI sio_hw->gpio_set = (uint32_t)(1 << AIN1_PIN) +#define AIN1_LO sio_hw->gpio_clr = (uint32_t)(1 << AIN1_PIN) + +#define AIN2_HI sio_hw->gpio_set = (uint32_t)(1 << AIN2_PIN) +#define AIN2_LO sio_hw->gpio_clr = (uint32_t)(1 << AIN2_PIN) + +#define BIN1_HI sio_hw->gpio_set = (uint32_t)(1 << BIN1_PIN) +#define BIN1_LO sio_hw->gpio_clr = (uint32_t)(1 << BIN1_PIN) + +#define BIN2_HI sio_hw->gpio_set = (uint32_t)(1 << BIN2_PIN) +#define BIN2_LO sio_hw->gpio_clr = (uint32_t)(1 << BIN2_PIN) + +// macros to set h-bridge dir states + +#define A_UP AIN2_LO; AIN1_HI +#define B_UP BIN2_LO; BIN1_HI + +#define A_OFF AIN2_LO; AIN1_LO +#define B_OFF BIN2_LO; BIN1_LO + +#define A_DOWN AIN1_LO; AIN2_HI +#define B_DOWN BIN1_LO; BIN2_HI + +// hardware pwm vals + +uint16_t sliceNumA; +uint16_t sliceNumB; +uint16_t channelA; +uint16_t channelB; + +void stepper_init(void){ + // -------------------------------------------- DIR PINS + // all of 'em, outputs + pinMode(AIN1_PIN, OUTPUT); + pinMode(AIN2_PIN, OUTPUT); + pinMode(BIN1_PIN, OUTPUT); + pinMode(BIN2_PIN, OUTPUT); + + gpio_set_function(APWM_PIN, GPIO_FUNC_PWM); + gpio_set_function(BPWM_PIN, GPIO_FUNC_PWM); + sliceNumA = pwm_gpio_to_slice_num(APWM_PIN); + sliceNumB = pwm_gpio_to_slice_num(BPWM_PIN); + channelA = pwm_gpio_to_channel(APWM_PIN); + channelB = pwm_gpio_to_channel(BPWM_PIN); + + // TODO: check about the old code, with Q ? + // or fk it, go full beans always ? + // uint32_t f_sys = clock_get_hz(clk_sys); + float divider = 1.0F; //(float)f_sys / (PWM_PERIOD * 10000UL); + + pwm_set_clkdiv(sliceNumA, divider); + pwm_set_clkdiv(sliceNumB, divider); + + // pwm period + pwm_set_wrap(sliceNumA, PWM_PERIOD); + pwm_set_wrap(sliceNumB, PWM_PERIOD); + + // set a start-up value of 1 / PWM_PERIOD + pwm_set_chan_level(sliceNumA, channelA, 1); + pwm_set_chan_level(sliceNumB, channelB, 1); + + // Set the PWM running + pwm_set_enabled(sliceNumA, true); + pwm_set_enabled(sliceNumB, true); +} + +void stepper_point(uint16_t phaseAngle, uint16_t amplitude){ + // wrap phaseAngle to 2048, and get a / b components + uint16_t coilAPhase = phaseAngle & 0b0000011111111111; + uint16_t coilBPhase = (phaseAngle + LUT_LENGTH / 2) & 0b0000011111111111; + + // clamp amplitude, + amplitude = amplitude & 0b0000001111111111; + + // a coil dir + if (coilAPhase > LUT_LENGTH){ + A_DOWN; + } else if (coilAPhase < LUT_LENGTH){ + A_UP; + } else { + A_OFF; + } + // b coil dir + if (coilBPhase > LUT_LENGTH){ + B_DOWN; + } else if (coilBPhase < LUT_LENGTH){ + B_UP; + } else { + B_OFF; + } + + // now we rectify each to the positive half wave, + coilAPhase = coilAPhase & 0b0000001111111111; + coilBPhase = coilBPhase & 0b0000001111111111; + + // expand to 32 for multiply overflow, + // then do fixed-point where 0-1.0 == 0-1024, using 2^10 bit divide + uint32_t coilAMag = (LUT[coilAPhase] * amplitude) >> 10; + uint32_t coilBMag = (LUT[coilBPhase] * amplitude) >> 10; + + // and set amplitudes... + pwm_set_chan_level(sliceNumA, channelA, coilAMag); + pwm_set_chan_level(sliceNumB, channelB, coilBMag); +} + +uint16_t _amplitude = 0; + +void stepper_point(uint16_t phaseAngle){ + stepper_point(phaseAngle, _amplitude); +} + +void stepper_setAmplitude(uint16_t amplitude){ + if(amplitude > 1024) amplitude = 1024; + if(amplitude < 0) amplitude = 0; + _amplitude = amplitude; +} \ No newline at end of file diff --git a/simple-stepper/stepperDriver.h b/simple-stepper/stepperDriver.h new file mode 100644 index 0000000000000000000000000000000000000000..dfc2186ddf8b348bcba049f87e3ab80fb59a7e8d --- /dev/null +++ b/simple-stepper/stepperDriver.h @@ -0,0 +1,34 @@ +/* +stepperDriver.h + +stepper code for two A4950s w/ VREF via TC -> RC Filters +with RP2040 support + +Jake Read & Quentin Bolsee at the Center for Bits and Atoms +(c) Massachusetts Institute of Technology 2023 + +This work may be reproduced, modified, distributed, performed, and +displayed for any purpose, but must acknowledge the squidworks and ponyo +projects. Copyright is retained and must be preserved. The work is provided as +is; no warranty is provided, and users accept all liability. +*/ + +#ifndef STEPPER_DRIVER_H_ +#define STEPPER_DRIVER_H_ + +#include <Arduino.h> +#include "pico/stdlib.h" +#include "hardware/pwm.h" + +// startup stepper hardware +void stepper_init(void); + +// mapping 0-2PI is 0-2048 and 0-1 is 0-1024 +void stepper_point(uint16_t phaseAngle, uint16_t amplitude); + +// or, omitting amplitude... +void stepper_point(uint16_t phaseAngle); + +void stepper_setAmplitude(uint16_t amplitude); + +#endif diff --git a/simple-stepper/stepperLUT.h b/simple-stepper/stepperLUT.h new file mode 100644 index 0000000000000000000000000000000000000000..82b338c4c81cdf3117f49d34715b6729807df7eb --- /dev/null +++ b/simple-stepper/stepperLUT.h @@ -0,0 +1,76 @@ +#ifndef STEPPER_LUT_H_ +#define STEPPER_LUT_H_ + +#include <Arduino.h> + +#define LUT_LENGTH 1024 +#define PWM_PERIOD 2048 + +const uint16_t LUT[LUT_LENGTH] = { + 0, 6, 13, 19, 25, 31, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, + 101, 107, 113, 119, 126, 132, 138, 145, 151, 157, 163, 170, 176, 182, 188, 195, + 201, 207, 213, 220, 226, 232, 238, 245, 251, 257, 263, 270, 276, 282, 288, 295, + 301, 307, 313, 319, 326, 332, 338, 344, 350, 357, 363, 369, 375, 381, 388, 394, + 400, 406, 412, 418, 425, 431, 437, 443, 449, 455, 461, 468, 474, 480, 486, 492, + 498, 504, 510, 516, 522, 529, 535, 541, 547, 553, 559, 565, 571, 577, 583, 589, + 595, 601, 607, 613, 619, 625, 631, 637, 643, 649, 655, 661, 667, 673, 679, 685, + 691, 697, 702, 708, 714, 720, 726, 732, 738, 744, 749, 755, 761, 767, 773, 779, + 784, 790, 796, 802, 808, 813, 819, 825, 831, 836, 842, 848, 854, 859, 865, 871, + 876, 882, 888, 893, 899, 905, 910, 916, 922, 927, 933, 938, 944, 950, 955, 961, + 966, 972, 977, 983, 988, 994, 999, 1005, 1010, 1016, 1021, 1027, 1032, 1038, 1043, 1048, + 1054, 1059, 1065, 1070, 1075, 1081, 1086, 1091, 1097, 1102, 1107, 1113, 1118, 1123, 1128, 1134, + 1139, 1144, 1149, 1154, 1160, 1165, 1170, 1175, 1180, 1185, 1191, 1196, 1201, 1206, 1211, 1216, + 1221, 1226, 1231, 1236, 1241, 1246, 1251, 1256, 1261, 1266, 1271, 1276, 1281, 1286, 1291, 1295, + 1300, 1305, 1310, 1315, 1320, 1324, 1329, 1334, 1339, 1344, 1348, 1353, 1358, 1362, 1367, 1372, + 1376, 1381, 1386, 1390, 1395, 1400, 1404, 1409, 1413, 1418, 1422, 1427, 1431, 1436, 1440, 1445, + 1449, 1454, 1458, 1463, 1467, 1471, 1476, 1480, 1484, 1489, 1493, 1497, 1502, 1506, 1510, 1514, + 1519, 1523, 1527, 1531, 1535, 1540, 1544, 1548, 1552, 1556, 1560, 1564, 1568, 1572, 1576, 1580, + 1584, 1588, 1592, 1596, 1600, 1604, 1608, 1612, 1616, 1620, 1623, 1627, 1631, 1635, 1639, 1642, + 1646, 1650, 1654, 1657, 1661, 1665, 1668, 1672, 1676, 1679, 1683, 1686, 1690, 1693, 1697, 1700, + 1704, 1707, 1711, 1714, 1718, 1721, 1725, 1728, 1731, 1735, 1738, 1741, 1745, 1748, 1751, 1754, + 1758, 1761, 1764, 1767, 1770, 1774, 1777, 1780, 1783, 1786, 1789, 1792, 1795, 1798, 1801, 1804, + 1807, 1810, 1813, 1816, 1819, 1822, 1825, 1827, 1830, 1833, 1836, 1839, 1841, 1844, 1847, 1850, + 1852, 1855, 1858, 1860, 1863, 1866, 1868, 1871, 1873, 1876, 1878, 1881, 1883, 1886, 1888, 1891, + 1893, 1895, 1898, 1900, 1902, 1905, 1907, 1909, 1912, 1914, 1916, 1918, 1921, 1923, 1925, 1927, + 1929, 1931, 1933, 1935, 1937, 1939, 1941, 1943, 1945, 1947, 1949, 1951, 1953, 1955, 1957, 1959, + 1961, 1962, 1964, 1966, 1968, 1969, 1971, 1973, 1975, 1976, 1978, 1979, 1981, 1983, 1984, 1986, + 1987, 1989, 1990, 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, + 2009, 2010, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, + 2026, 2027, 2028, 2029, 2030, 2031, 2031, 2032, 2033, 2034, 2034, 2035, 2036, 2037, 2037, 2038, + 2038, 2039, 2040, 2040, 2041, 2041, 2042, 2042, 2043, 2043, 2044, 2044, 2044, 2045, 2045, 2045, + 2046, 2046, 2046, 2046, 2047, 2047, 2047, 2047, 2047, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2047, 2047, 2047, 2047, 2047, 2046, 2046, 2046, 2046, + 2045, 2045, 2045, 2044, 2044, 2044, 2043, 2043, 2042, 2042, 2041, 2041, 2040, 2040, 2039, 2038, + 2038, 2037, 2037, 2036, 2035, 2034, 2034, 2033, 2032, 2031, 2031, 2030, 2029, 2028, 2027, 2026, + 2025, 2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2010, 2009, + 2008, 2007, 2005, 2004, 2003, 2002, 2000, 1999, 1997, 1996, 1995, 1993, 1992, 1990, 1989, 1987, + 1986, 1984, 1983, 1981, 1979, 1978, 1976, 1975, 1973, 1971, 1969, 1968, 1966, 1964, 1962, 1961, + 1959, 1957, 1955, 1953, 1951, 1949, 1947, 1945, 1943, 1941, 1939, 1937, 1935, 1933, 1931, 1929, + 1927, 1925, 1923, 1921, 1918, 1916, 1914, 1912, 1909, 1907, 1905, 1902, 1900, 1898, 1895, 1893, + 1891, 1888, 1886, 1883, 1881, 1878, 1876, 1873, 1871, 1868, 1866, 1863, 1860, 1858, 1855, 1852, + 1850, 1847, 1844, 1841, 1839, 1836, 1833, 1830, 1827, 1825, 1822, 1819, 1816, 1813, 1810, 1807, + 1804, 1801, 1798, 1795, 1792, 1789, 1786, 1783, 1780, 1777, 1774, 1770, 1767, 1764, 1761, 1758, + 1754, 1751, 1748, 1745, 1741, 1738, 1735, 1731, 1728, 1725, 1721, 1718, 1714, 1711, 1707, 1704, + 1700, 1697, 1693, 1690, 1686, 1683, 1679, 1676, 1672, 1668, 1665, 1661, 1657, 1654, 1650, 1646, + 1642, 1639, 1635, 1631, 1627, 1623, 1620, 1616, 1612, 1608, 1604, 1600, 1596, 1592, 1588, 1584, + 1580, 1576, 1572, 1568, 1564, 1560, 1556, 1552, 1548, 1544, 1540, 1535, 1531, 1527, 1523, 1519, + 1514, 1510, 1506, 1502, 1497, 1493, 1489, 1484, 1480, 1476, 1471, 1467, 1463, 1458, 1454, 1449, + 1445, 1440, 1436, 1431, 1427, 1422, 1418, 1413, 1409, 1404, 1400, 1395, 1390, 1386, 1381, 1376, + 1372, 1367, 1362, 1358, 1353, 1348, 1344, 1339, 1334, 1329, 1324, 1320, 1315, 1310, 1305, 1300, + 1295, 1291, 1286, 1281, 1276, 1271, 1266, 1261, 1256, 1251, 1246, 1241, 1236, 1231, 1226, 1221, + 1216, 1211, 1206, 1201, 1196, 1191, 1185, 1180, 1175, 1170, 1165, 1160, 1154, 1149, 1144, 1139, + 1134, 1128, 1123, 1118, 1113, 1107, 1102, 1097, 1091, 1086, 1081, 1075, 1070, 1065, 1059, 1054, + 1048, 1043, 1038, 1032, 1027, 1021, 1016, 1010, 1005, 999, 994, 988, 983, 977, 972, 966, + 961, 955, 950, 944, 938, 933, 927, 922, 916, 910, 905, 899, 893, 888, 882, 876, + 871, 865, 859, 854, 848, 842, 836, 831, 825, 819, 813, 808, 802, 796, 790, 784, + 779, 773, 767, 761, 755, 749, 744, 738, 732, 726, 720, 714, 708, 702, 697, 691, + 685, 679, 673, 667, 661, 655, 649, 643, 637, 631, 625, 619, 613, 607, 601, 595, + 589, 583, 577, 571, 565, 559, 553, 547, 541, 535, 529, 522, 516, 510, 504, 498, + 492, 486, 480, 474, 468, 461, 455, 449, 443, 437, 431, 425, 418, 412, 406, 400, + 394, 388, 381, 375, 369, 363, 357, 350, 344, 338, 332, 326, 319, 313, 307, 301, + 295, 288, 282, 276, 270, 263, 257, 251, 245, 238, 232, 226, 220, 213, 207, 201, + 195, 188, 182, 176, 170, 163, 157, 151, 145, 138, 132, 126, 119, 113, 107, 101, + 94, 88, 82, 75, 69, 63, 57, 50, 44, 38, 31, 25, 19, 13, 6, 0, +}; + +#endif \ No newline at end of file