diff --git a/src/arduino/simhaptic/Makefile b/src/arduino/simhaptic/Makefile new file mode 100644 index 0000000..bfd2e90 --- /dev/null +++ b/src/arduino/simhaptic/Makefile @@ -0,0 +1,166 @@ +# Makefile for Arduino based scketches +# +# Copyright 2020 Valerio Di Giampietro http://va.ler.io v@ler.io +# MIT License - see License.txt file +# +# This Makefile uses the arduino-cli, the Arduino command line interface +# and has been designed and tested to run on Linux, not on Windows. +# Probably it will run on a Mac, but it has not been tested. +# +# Please note that: +# +# 1. each sketch must reside in his own folder with this Makefile +# +# 2. the main make targets are: +# - all compiles and upload +# - compile compiles only +# - upload upload via serial port, compile if the binary file is +# not available +# - ota upload Over The Air, automatically find the device +# IP address using the IOT_NAME (device hostname) +# - clean clean the build directory +# - find find OTA updatable devices on the local subnet +# - requirements it the file "requirements.txt" exists it will +# install the libraries listed in this file +# +# default is "all" +# +# 3. it gets the name of the sketch using the wildcard make command; +# the name is *.ino; this means that you must have ONLY a file +# with .ino extension, otherwise this makefile will break. This +# also means that you can use this Makefile, almost unmodified, +# for any sketch as long as you keep a single .ino file in each +# folder +# +# 4. you can split your project in multiple files, if you wish, +# using a single .ino file and multiple .h files, that you can +# include in the .ino file with an '#include "myfile.h"' +# directive +# +# Optionally some environment variables can be set: +# +# FQBN Fully Qualified Board Name; if not set in the environment +# it will be assigned a value in this makefile +# +# SERIAL_DEV Serial device to upload the sketch; if not set in the +# environment it will be assigned: +# /dev/ttyUSB0 if it exists, or +# /dev/ttyACM0 if it exists, or +# unknown +# +# IOT_NAME Name of the IOT device; if not set in the environment +# it will be assigned a value in this makefile. This is +# very useful for OTA update, the device will be searched +# on the local subnet using this name +# +# OTA_PORT Port used by OTA update; if not set in the environment +# it will be assigned the default value of 8266 in this +# makefile +# +# OTA_PASS Password used for OTA update; if not set in the environment +# it will be assigned the default value of an empty string +# +# V verbose flag; can be 0 (quiet) or 1 (verbose); if not set +# in the environment it will be assigned a default value +# in this makefile + + +MAKE_DIR := $(PWD) +# +# ----- setup wor Wemos D1 mini ----- +#FQBN ?= esp8266:esp8266:d1_mini +#IOT_NAME ?= esp8266-meteo +#OTA_PORT ?= 8266 +#OTA_PASS ?= +# ----- setup for Arduino Uno +FQBN ?= arduino:avr:uno +# ----- --------------------- +V ?= 0 +VFLAG = + +ifeq "$(V)" "1" +VFLAG =-v +endif + +ifndef SERIAL_DEV + ifneq (,$(wildcard /dev/ttyUSB0)) + SERIAL_DEV = /dev/ttyUSB0 + else ifneq (,$(wildcard /dev/ttyACM0)) + SERIAL_DEV = /dev/ttyACM0 + else + SERIAL_DEV = unknown + endif +endif + +BUILD_DIR := $(subst :,.,build/$(FQBN)) + +SRC := $(wildcard *.ino) +HDRS := $(wildcard *.h) +BIN := $(BUILD_DIR)/$(SRC).bin +ELF := $(BUILD_DIR)/$(SRC).elf + +$(info FQBN is [${FQBN}]) +$(info IOT_NAME is [${IOT_NAME}]) +$(info OTA_PORT is [${OTA_PORT}]) +$(info OTA_PASS is [${OTA_PASS}]) +$(info V is [${V}]) +$(info VFLAG is [${VFLAG}]) +$(info MAKE_DIR is [${MAKE_DIR}]) +$(info BUILD_DIR is [${BUILD_DIR}]) +$(info SRC is [${SRC}]) +$(info HDRS is [${HDRS}]) +$(info BIN is [${BIN}]) +$(info SERIAL_DEV is [${SERIAL_DEV}]) + +all: $(ELF) upload +.PHONY: all + +compile: $(ELF) +.PHONY: compile + +$(ELF): $(SRC) $(HDRS) + arduino-cli compile -b $(FQBN) $(VFLAG) + @if which arduino-manifest.pl; \ + then echo "---> Generating manifest.txt"; \ + arduino-manifest.pl -b $(FQBN) $(SRC) $(HDRS) > manifest.txt; \ + else echo "---> If you want to generate manifest.txt, listing used libraries and their versions,"; \ + echo "---> please install arduino-manifest, see https://github.com/digiampietro/arduino-manifest"; \ + fi + +upload: + @if [ ! -c $(SERIAL_DEV) ] ; \ + then echo "---> ERROR: Serial Device not available, please set the SERIAL_DEV environment variable" ; \ + else echo "---> Uploading sketch\n"; \ + arduino-cli upload -b $(FQBN) -p $(SERIAL_DEV) $(VFLAG); \ + fi + +ota: + @PLAT_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.platform.path' | awk -F= '{print $$2}'` ; \ + PY_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.tools.python3.path' | awk -F= '{print $$2}'` ; \ + IOT_IP=`avahi-browse _arduino._tcp --resolve --parsable --terminate|grep -i ';$(IOT_NAME);'|grep ';$(OTA_PORT);'| awk -F\; '{print $$8}'|head -1`; \ + BINFILE=$(wildcard $(BUILD_DIR)/$(SRC)*bin); \ + echo "PLAT_PATH is [$$PLAT_PATH]" ; \ + echo "PY_PATH: is [$$PY_PATH]" ; \ + echo "IOT_IP: is [$$IOT_IP]" ; \ + echo "BINFILE: is [$$BINFILE]" ; \ + if [ "$$IOT_IP" = "" ] ; \ + then echo "Unable to find device IP. Check that the IOT_NAME environment variable is correctly set. Use 'make find' to search devices"; \ + else echo "---> Uploading Over The Air"; \ + $$PY_PATH/python3 $$PLAT_PATH/tools/espota.py -i $$IOT_IP -p $(OTA_PORT) --auth=$(OTA_PASS) -f $$BINFILE ;\ + fi + +clean: + @echo "---> Cleaning the build directory" + rm -rf build + +find: + avahi-browse _arduino._tcp --resolve --parsable --terminate + +requirements: + @if [ -e requirements.txt ]; \ + then while read -r i ; do echo ; \ + echo "---> Installing " '"'$$i'"' ; \ + arduino-cli lib install "$$i" ; \ + done < requirements.txt ; \ + else echo "---> MISSING requirements.txt file"; \ + fi diff --git a/src/arduino/simhaptic/simdata.h b/src/arduino/simhaptic/simdata.h new file mode 120000 index 0000000..56bde08 --- /dev/null +++ b/src/arduino/simhaptic/simdata.h @@ -0,0 +1 @@ +../../monocoque/simulatorapi/simapi/simapi/simdata.h \ No newline at end of file diff --git a/src/arduino/simhaptic/simhaptic.h b/src/arduino/simhaptic/simhaptic.h new file mode 100755 index 0000000..ebb9cfc --- /dev/null +++ b/src/arduino/simhaptic/simhaptic.h @@ -0,0 +1,16 @@ +#ifndef _SIMHAPTICDATA_H +#define _SIMHAPTICDATA_H + +#include +#include + +typedef struct +{ + int motor; + float effect; + float power; +} +SimHapticData; + + +#endif diff --git a/src/arduino/simhaptic/simhaptic.ino b/src/arduino/simhaptic/simhaptic.ino new file mode 100644 index 0000000..f85824f --- /dev/null +++ b/src/arduino/simhaptic/simhaptic.ino @@ -0,0 +1,85 @@ +#include +#include "simhaptic.h" + +#define BYTE_SIZE sizeof(SimHapticData) +#define POWER .6 + +Adafruit_MotorShield AFMS = Adafruit_MotorShield(); + +Adafruit_DCMotor *myMotor1 = AFMS.getMotor(1); +//Adafruit_DCMotor *myMotor2 = AFMS.getMotor(2); +Adafruit_DCMotor *myMotor3 = AFMS.getMotor(3); +//Adafruit_DCMotor *myMotor4 = AFMS.getMotor(4); + +SimHapticData sd; +int velocity = 0; + +void setup() { + Serial.begin(9600); + if (!AFMS.begin()) { + Serial.println("Could not find Motor Shield. Check wiring."); + while (1); + } + sd.velocity = 10; + + myMotor1->setSpeed(0); + myMotor1->run(FORWARD); + + //myMotor2->setSpeed(0); + //myMotor2->run(FORWARD); + + myMotor3->setSpeed(0); + myMotor3->run(FORWARD); + + //myMotor4->setSpeed(0); + //myMotor4->run(FORWARD); +} + +void loop() { + char buff[BYTE_SIZE]; + + if (Serial.available() >= BYTE_SIZE) + { + Serial.readBytes(buff, BYTE_SIZE); + memcpy(&sd, &buff, BYTE_SIZE); + velocity = sd.velocity; + } + int v = ceil(effect * 255); + if (v >= 255) + { + v = 255; + } + + MOTOR_1 = 0, + MOTOR_2 = 1, + MOTOR_3 = 2, + MOTOR_4 = 3, + MOTOR_1_4 = 4, + MOTOR_2_4 = 5, + MOTOR_3_4 = 6, + MOTOR_1_2 = 7, + MOTOR_1_3 = 8, + MOTOR_2_3 = 9, + MOTOR_1_2_3_4 = 10, + MOTOR_1_2_3 = 11, + MOTOR_2_3_4 = 12, + MOTOR_1_2_4 = 13, + MOTOR_1_3_4 = 14 + + if (motor == 0 || motor == 4 || motor == 7 || motor == 8 || motor == 10 || motor == 11 || motor == 13 || motor == 14) + { + myMotor1->setSpeed(v*POWER); + } + //if (motor == 1 || motor == 5 || motor = 7 || motor == 9 || motor == 10 || motor == 11 || motor == 12 || motor = 13) + //{ + // myMotor2->setSpeed(v*POWER); + //} + if (motor == 2 || motor == 6 || motor = 8 || motor == 9 || motor == 10 || motor == 11 || motor == 12 || motor = 14) + { + myMotor3->setSpeed(v*POWER); + } + //if (motor == 3 || motor == 4 || motor = 5 || motor == 6 || motor == 10 || motor == 12 || motor == 13 || motor = 14) + //{ + // myMotor4->setSpeed(v*POWER); + //} +} diff --git a/src/monocoque/devices/hapticeffect.c b/src/monocoque/devices/hapticeffect.c index bcfb6b7..810f87e 100644 --- a/src/monocoque/devices/hapticeffect.c +++ b/src/monocoque/devices/hapticeffect.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "usbhapticdevice.h" #include "../../helper/confighelper.h" @@ -282,9 +283,9 @@ void getTyreDiameter(SimData* simdata) } -int slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int useconfig, int* configcheck, char* configfile) +double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int useconfig, int* configcheck, char* configfile) { - int play = 0; + double play = 0; double wheelslip[4]; wheelslip[0] = 0; wheelslip[1] = 0; @@ -349,28 +350,28 @@ int slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int { if(wheelslip[0] < -threshold) { - play++; + play += fabs(wheelslip[0]) - fabs(threshold); } } if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR) { if(wheelslip[1] < -threshold) { - play++; + play += fabs(wheelslip[1]) - fabs(threshold); } } if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR) { if(wheelslip[2] < -threshold) { - play++; + play += fabs(wheelslip[2]) - fabs(threshold); } } if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR) { if(wheelslip[3] < -threshold) { - play++; + play += fabs(wheelslip[3]) - fabs(threshold); } } @@ -381,28 +382,28 @@ int slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int { if(wheelslip[0] > threshold) { - play++; + play += wheelslip[0] - threshold; } } if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR) { if(wheelslip[1] > threshold) { - play++; + play += wheelslip[1] - threshold; } } if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR) { if(wheelslip[2] > threshold) { - play++; + play += wheelslip[2] - threshold; } } if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR) { if(wheelslip[3] > threshold) { - play++; + play += wheelslip[3] - threshold; } } @@ -413,28 +414,28 @@ int slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int { if(wheelslip[0] > threshold) { - play++; + play += wheelslip[0] - threshold; } } if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR) { if(wheelslip[1] > threshold) { - play++; + play += wheelslip[1] - threshold; } } if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR) { if(wheelslip[2] > threshold) { - play++; + play += wheelslip[2] - threshold; } } if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR) { if(wheelslip[3] > threshold) { - play++; + play += wheelslip[3] - threshold; } } if(simdata->abs <= 0) diff --git a/src/monocoque/devices/serialdevice.c b/src/monocoque/devices/serialdevice.c index 5505fa6..5cd983e 100644 --- a/src/monocoque/devices/serialdevice.c +++ b/src/monocoque/devices/serialdevice.c @@ -55,14 +55,16 @@ int arduino_simwind_update(SimDevice* this, SimData* simdata) return result; } -int arduino_haptic_update(SimDevice* this, SimData* simdata) +int arduino_simhaptic_update(SimDevice* this, SimData* simdata) { SerialDevice* serialdevice = (void *) this->derived; int result = 1; - int play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig); + double play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig); slogt("Updating arduino haptic device"); + serialdevice->u.simhapticdata.power = 0.6; + serialdevice->u.simhapticdata.motor = serialdevice->motorsposition; arduino_update(serialdevice, simdata, sizeof(SimData)); @@ -79,7 +81,7 @@ int serialdev_free(SimDevice* this) return 0; } -int serialdev_init(SerialDevice* serialdevice, const char* portdev) +int serialdev_init(SerialDevice* serialdevice, const char* portdev, int motorsposition) { slogi("initializing serial device..."); int error = 0; @@ -87,6 +89,8 @@ int serialdev_init(SerialDevice* serialdevice, const char* portdev) serialdevice->type = SERIALDEV_UNKNOWN; serialdevice->type = SERIALDEV_ARDUINO; + serialdevice->motorsposition = motorsposition; + error = arduino_init(serialdevice, portdev); return error; @@ -95,7 +99,7 @@ int serialdev_init(SerialDevice* serialdevice, const char* portdev) static const vtable serial_simdevice_vtable = { &serialdev_update, &serialdev_free }; static const vtable arduino_shiftlights_vtable = { &arduino_shiftlights_update, &serialdev_free }; static const vtable arduino_simwind_vtable = { &arduino_simwind_update, &serialdev_free }; -static const vtable arduino_haptic_vtable = { &arduino_haptic_update, &serialdev_free }; +static const vtable arduino_simhaptic_vtable = { &arduino_simhaptic_update, &serialdev_free }; SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) { @@ -120,7 +124,7 @@ SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) { break; case (SIMDEVTYPE_SERIALHAPTIC): this->devicetype = ARDUINODEV__HAPTIC; - this->m.vtable = &arduino_haptic_vtable; + this->m.vtable = &arduino_simhaptic_vtable; slogi("Initializing arduino device for haptic effects."); break; } @@ -135,7 +139,7 @@ SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) { this->m.hapticeffect.tyrediameterconfig = ms->tyre_diameter_config; } - int error = serialdev_init(this, ds->serialdevsettings.portdev); + int error = serialdev_init(this, ds->serialdevsettings.portdev, ds->serialdevsettings.motorsposition); if (error != 0) { diff --git a/src/monocoque/devices/simdevice.h b/src/monocoque/devices/simdevice.h index 3696376..e4f9442 100644 --- a/src/monocoque/devices/simdevice.h +++ b/src/monocoque/devices/simdevice.h @@ -11,6 +11,7 @@ #include "../simulatorapi/simapi/simapi/simdata.h" #include "../../arduino/simwind/simwind.h" +#include "../../arduino/simhaptic/simhaptic.h" #include "../../arduino/shiftlights/shiftlights.h" typedef struct SimDevice SimDevice; @@ -46,10 +47,12 @@ typedef struct int id; SerialType type; struct sp_port* port; + int motorsposition; SerialDeviceType devicetype; union { SimWindData simwinddata; + SimHapticData simhapticdata; ShiftLightsData shiftlightsdata; } u; } @@ -57,7 +60,7 @@ SerialDevice; int arduino_shiftlights_update(SimDevice* this, SimData* simdata); int arduino_simwind_update(SimDevice* this, SimData* simdata); -int arduino_haptic_update(SimDevice* this, SimData* simdata); +int arduino_simhaptic_update(SimDevice* this, SimData* simdata); int serialdev_free(SimDevice* this); SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms); diff --git a/src/monocoque/devices/usbhapticdevice.c b/src/monocoque/devices/usbhapticdevice.c index a160b30..c8320b6 100644 --- a/src/monocoque/devices/usbhapticdevice.c +++ b/src/monocoque/devices/usbhapticdevice.c @@ -14,17 +14,19 @@ int usbhapticdev_update(USBGenericHapticDevice* usbhapticdevice, SimData* simdata, int tyre, int useconfig, int* configcheck, char* configfile) { - int play = slipeffect(simdata, usbhapticdevice->effecttype, tyre, usbhapticdevice->threshold, useconfig, configcheck, configfile); + double play = slipeffect(simdata, usbhapticdevice->effecttype, tyre, usbhapticdevice->threshold, useconfig, configcheck, configfile); if (play != usbhapticdevice->state) { + int rplay = 0; if(play > 0) { - cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, play); + rplay = 1; + cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay); } else { - cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, play); + cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay); } usbhapticdevice->state = play; } diff --git a/src/monocoque/helper/confighelper.c b/src/monocoque/helper/confighelper.c index 0fcf398..241bb1f 100644 --- a/src/monocoque/helper/confighelper.c +++ b/src/monocoque/helper/confighelper.c @@ -341,7 +341,8 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co // logic for different devices } - if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC || ds->dev_type == SIMDEV_SOUND || ds->dev_type == SIMDEVTYPE_SERIALHAPTIC ) { + if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC || ds->dev_type == SIMDEV_SOUND || ds->dev_type == SIMDEVTYPE_SERIALHAPTIC) + { const char* effect; config_setting_lookup_string(device_settings, "effect", &effect); strtoeffecttype(effect, ds); @@ -388,14 +389,19 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co } } - if (ds->dev_subtype == SIMDEVTYPE_SIMWIND || ds->dev_subtype == SIMDEVTYPE_SHIFTLIGHTS) + if (ds->dev_subtype == SIMDEVTYPE_SIMWIND || ds->dev_subtype == SIMDEVTYPE_SHIFTLIGHTS || ds->dev_subtype == SIMDEVTYPE_SERIALHAPTIC) { if (device_settings != NULL) { const char* temp; config_setting_lookup_string(device_settings, "devpath", &temp); ds->serialdevsettings.portdev = strdup(temp); + + int motorposition = 8; + config_setting_lookup_int(device_settings, "motors", &motorposition); + ds->serialdevsettings.motorsposition = motorposition; } + } return error; diff --git a/src/monocoque/helper/confighelper.h b/src/monocoque/helper/confighelper.h index 0fc6dea..fc80197 100644 --- a/src/monocoque/helper/confighelper.h +++ b/src/monocoque/helper/confighelper.h @@ -51,6 +51,26 @@ typedef enum } VibrationEffectType; +typedef enum +{ + MOTOR_1 = 0, + MOTOR_2 = 1, + MOTOR_3 = 2, + MOTOR_4 = 3, + MOTOR_1_4 = 4, + MOTOR_2_4 = 5, + MOTOR_3_4 = 6, + MOTOR_1_2 = 7, + MOTOR_1_3 = 8, + MOTOR_2_3 = 9, + MOTOR_1_2_3_4 = 10, + MOTOR_1_2_3 = 11, + MOTOR_2_3_4 = 12, + MOTOR_1_2_4 = 13, + MOTOR_1_3_4 = 14 +} +MotorPosition; + typedef enum { MONOCOQUE_ERROR_NONE = 0, @@ -97,6 +117,7 @@ TachometerSettings; typedef struct { char* portdev; + MotorPosition motorsposition; } SerialDeviceSettings;