Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Alejandro Butron
Published © GPL3+

IoT Rail Vibration Generator

With this device, rail vibration is generated for measuring the movement and transmitting the data for later analysis.

BeginnerWork in progress5 hours192
IoT Rail Vibration Generator

Things used in this project

Hardware components

AVR IoT Mini Cellular Board
Microchip AVR IoT Mini Cellular Board
×1
WT901C-TTL 9-Axis vibration accelerometer
×1
Dual H-Bridge motor drivers L298
SparkFun Dual H-Bridge motor drivers L298
×1
3.3V to 5V level converter
×2
DC motor, 12 V
×2
Breadboard (generic)
Breadboard (generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Steel profile
×1
Steel spring
×2

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Drill / Driver, 20V
Drill / Driver, 20V

Story

Read more

Schematics

AVR 128DB48 rail vibration sensing device

Diagram for connecting an AVR 128DB48 IoT board with an H-Bridge dc motor driver and the WT901C vibration sensor.

Code

Test program for sending the WT901 sensor data to the AVR 128DB48.

Arduino
First test for sending the WT901 sensor data. For some reason, the hardware serial on the UART2 didn't work, so we turn to the software serial.
/*
Test for the AVR 128DB48IoT and the WT901C TTL sensor.
Using sofware serial.

WT901CTTL      128DB48 IoT
    VCC <--->  3.3V
    TX  <--->  PF5 (RX2)
    RX  <--->  PF4 (TX2)
    GND <--->  GND

    21 de marzo de 2024
*/

#include <SoftwareSerial.h>
#include <REG.h>
#include <wit_c_sdk.h>

#define ACC_UPDATE		0x01
#define GYRO_UPDATE		0x02
#define ANGLE_UPDATE	0x04
#define MAG_UPDATE		0x08
#define READ_UPDATE		0x80
static volatile char s_cDataUpdate = 0, s_cCmd = 0xff; 

static void CmdProcess(void);
static void AutoScanSensor(void);
static void SensorUartSend(uint8_t *p_data, uint32_t uiSize);
static void SensorDataUpdata(uint32_t uiReg, uint32_t uiRegNum);
static void Delayms(uint16_t ucMs);
const uint32_t c_uiBaud[8] = {0,4800, 9600, 19200, 38400, 57600, 115200, 230400};

SoftwareSerial mySerial(PIN_PF5, PIN_PF4); // RX, TX

void setup() {
  Serial3.begin(115200);
  mySerial.begin(9600); // BaudRate
	WitInit(WIT_PROTOCOL_NORMAL, 0x50);
	WitSerialWriteRegister(SensorUartSend);
	WitRegisterCallBack(SensorDataUpdata);
  WitDelayMsRegister(Delayms);
	Serial3.print("\r\n** wit-motion normal example **\r\n");
	AutoScanSensor();
}

int i;
float fAcc[3], fGyro[3], fAngle[3];
void loop() {
    while (mySerial.available())
    {
      WitSerialDataIn(mySerial.read());
    }
    while (Serial3.available()) 
    {
      CopeCmdData(Serial3.read());
    }
		CmdProcess();
		if(s_cDataUpdate)
		{
			for(i = 0; i < 3; i++)
			{
				fAcc[i] = sReg[AX+i] / 32768.0f * 16.0f;
				fGyro[i] = sReg[GX+i] / 32768.0f * 2000.0f;
				fAngle[i] = sReg[Roll+i] / 32768.0f * 180.0f;
			}
			if(s_cDataUpdate & ACC_UPDATE)
			{
				Serial3.print("acc:");
				Serial3.print(fAcc[0], 3);
				Serial3.print(" ");
				Serial3.print(fAcc[1], 3);
				Serial3.print(" ");
				Serial3.print(fAcc[2], 3);
				Serial3.print("\r\n");
				s_cDataUpdate &= ~ACC_UPDATE;
			}
			if(s_cDataUpdate & GYRO_UPDATE)
			{
				Serial3.print("gyro:");
				Serial3.print(fGyro[0], 1);
				Serial3.print(" ");
				Serial3.print(fGyro[1], 1);
				Serial3.print(" ");
				Serial3.print(fGyro[2], 1);
				Serial3.print("\r\n");
				s_cDataUpdate &= ~GYRO_UPDATE;
			}
			if(s_cDataUpdate & ANGLE_UPDATE)
			{
				Serial3.print("angle:");
				Serial3.print(fAngle[0], 3);
				Serial3.print(" ");
				Serial3.print(fAngle[1], 3);
				Serial3.print(" ");
				Serial3.print(fAngle[2], 3);
				Serial3.print("\r\n");
				s_cDataUpdate &= ~ANGLE_UPDATE;
			}
			if(s_cDataUpdate & MAG_UPDATE)
			{
				Serial3.print("mag:");
				Serial3.print(sReg[HX]);
				Serial3.print(" ");
				Serial3.print(sReg[HY]);
				Serial3.print(" ");
				Serial3.print(sReg[HZ]);
				Serial3.print("\r\n");
				s_cDataUpdate &= ~MAG_UPDATE;
			}
      s_cDataUpdate = 0;
		}
}

void CopeCmdData(unsigned char ucData){
	static unsigned char s_ucData[50], s_ucRxCnt = 0;
	
	s_ucData[s_ucRxCnt++] = ucData;
	if(s_ucRxCnt<3)return;										//Less than three data returned
	if(s_ucRxCnt >= 50) s_ucRxCnt = 0;
	if(s_ucRxCnt >= 3)
	{
		if((s_ucData[1] == '\r') && (s_ucData[2] == '\n'))
		{
			s_cCmd = s_ucData[0];
			memset(s_ucData,0,50);
			s_ucRxCnt = 0;
		}
		else 
		{
			s_ucData[0] = s_ucData[1];
			s_ucData[1] = s_ucData[2];
			s_ucRxCnt = 2;
			
		}
	}
}

static void ShowHelp(void){
	Serial3.print("\r\n************************	 WIT_SDK_DEMO	************************");
	Serial3.print("\r\n************************          HELP           ************************\r\n");
	Serial3.print("UART SEND:a\\r\\n   Acceleration calibration.\r\n");
	Serial3.print("UART SEND:m\\r\\n   Magnetic field calibration,After calibration send:   e\\r\\n   to indicate the end\r\n");
	Serial3.print("UART SEND:U\\r\\n   Bandwidth increase.\r\n");
	Serial3.print("UART SEND:u\\r\\n   Bandwidth reduction.\r\n");
	Serial3.print("UART SEND:B\\r\\n   Baud rate increased to 115200.\r\n");
	Serial3.print("UART SEND:b\\r\\n   Baud rate reduction to 9600.\r\n");
	Serial3.print("UART SEND:R\\r\\n   The return rate increases to 10Hz.\r\n");
  Serial3.print("UART SEND:r\\r\\n   The return rate reduction to 1Hz.\r\n");
  Serial3.print("UART SEND:C\\r\\n   Basic return content: acceleration, angular velocity, angle, magnetic field.\r\n");
  Serial3.print("UART SEND:c\\r\\n   Return content: acceleration.\r\n");
  Serial3.print("UART SEND:h\\r\\n   help.\r\n");
	Serial3.print("******************************************************************************\r\n");
}

static void CmdProcess(void){
	switch(s_cCmd)
	{
		case 'a':	if(WitStartAccCali() != WIT_HAL_OK) Serial3.print("\r\nSet AccCali Error\r\n");
			break;
		case 'm':	if(WitStartMagCali() != WIT_HAL_OK) Serial3.print("\r\nSet MagCali Error\r\n");
			break;
		case 'e':	if(WitStopMagCali() != WIT_HAL_OK) Serial3.print("\r\nSet MagCali Error\r\n");
			break;
		case 'u':	if(WitSetBandwidth(BANDWIDTH_5HZ) != WIT_HAL_OK) Serial3.print("\r\nSet Bandwidth Error\r\n");
			break;
		case 'U':	if(WitSetBandwidth(BANDWIDTH_256HZ) != WIT_HAL_OK) Serial3.print("\r\nSet Bandwidth Error\r\n");
			break;
		case 'B':	if(WitSetUartBaud(WIT_BAUD_115200) != WIT_HAL_OK) Serial3.print("\r\nSet Baud Error\r\n");
              else 
              {
                mySerial.begin(c_uiBaud[WIT_BAUD_115200]);
                Serial3.print(" 115200 Baud rate modified successfully\r\n");
              }
			break;
		case 'b':	if(WitSetUartBaud(WIT_BAUD_9600) != WIT_HAL_OK) Serial3.print("\r\nSet Baud Error\r\n");
              else 
              {
                mySerial.begin(c_uiBaud[WIT_BAUD_9600]); 
                Serial3.print(" 9600 Baud rate modified successfully\r\n");
              }
			break;
		case 'r': if(WitSetOutputRate(RRATE_1HZ) != WIT_HAL_OK) Serial3.print("\r\nSet Baud Error\r\n");
			        else Serial3.print("\r\nSet Baud Success\r\n");
			break;
		case 'R':	if(WitSetOutputRate(RRATE_10HZ) != WIT_HAL_OK) Serial3.print("\r\nSet Baud Error\r\n");
              else Serial3.print("\r\nSet Baud Success\r\n");
			break;
    case 'C': if(WitSetContent(RSW_ACC|RSW_GYRO|RSW_ANGLE|RSW_MAG) != WIT_HAL_OK) Serial.print("\r\nSet RSW Error\r\n");
      break;
    case 'c': if(WitSetContent(RSW_ACC) != WIT_HAL_OK) Serial3.print("\r\nSet RSW Error\r\n");
      break;
		case 'h':	ShowHelp();
			break;
		default :break;
	}
	s_cCmd = 0xff;
}

static void SensorUartSend(uint8_t *p_data, uint32_t uiSize){
  mySerial.write(p_data, uiSize);
  mySerial.flush();
}

static void Delayms(uint16_t ucMs){
  delay(ucMs);
}

static void SensorDataUpdata(uint32_t uiReg, uint32_t uiRegNum){
	int i;
    for(i = 0; i < uiRegNum; i++)
    {
        switch(uiReg)
        {
            case AZ:
				s_cDataUpdate |= ACC_UPDATE;
            break;
            case GZ:
				s_cDataUpdate |= GYRO_UPDATE;
            break;
            case HZ:
				s_cDataUpdate |= MAG_UPDATE;
            break;
            case Yaw:
				s_cDataUpdate |= ANGLE_UPDATE;
            break;
            default:
				s_cDataUpdate |= READ_UPDATE;
			break;
        }
		uiReg++;
    }
}

static void AutoScanSensor(void){
	int i, iRetry;
	
	for(i = 0; i < sizeof(c_uiBaud)/sizeof(c_uiBaud[0]); i++)
	{
		mySerial.begin(c_uiBaud[i]);
    mySerial.flush();
		iRetry = 2;
		s_cDataUpdate = 0;
		do
		{
			WitReadReg(AX, 3);
			delay(200);
      while (mySerial.available())
      {
        WitSerialDataIn(mySerial.read());
      }
			if(s_cDataUpdate != 0)
			{
				Serial3.print(c_uiBaud[i]);
				Serial3.print(" baud find sensor\r\n\r\n");
				ShowHelp();
				return ;
			}
			iRetry--;
		}while(iRetry);		
	}
	Serial3.print("can not find sensor\r\n");
	Serial3.print("please check your connection\r\n");
}

PWM test program for one motor

Arduino
PWM signal is generated with the analogWrite instruction. The duty cycle is increased with switch 0, up to 250.
/*
 * PWM test program for one motor. The duty cycle is increased with the switch 0.
 * 
 * March 31st, 2024
 */

#include <Arduino.h>

#define IN1 PIN_PD3   // A2
#define IN2 PIN_PD4   // A3
#define PWM1 PIN_PD5  // A4
#define IN3 PIN_PE2   // D5
#define IN4 PIN_PE1   // D6
#define PWM2 PIN_PD0  // D9

/**
 * @brief Note that it is important that variables modified in an interrupt are
 * volatile, so that the compiler don't optimize them away.
 */
static volatile bool button_pressed = false;

/**
 * @brief Gets called when the SW0 button is pressed.
 */
static void buttonInterrupt(void) { button_pressed = true; }

// setting PWM properties
int dutyCycle = 150;

void setup() {
  pinConfigure(IN1, PIN_DIR_OUTPUT);      // IN1
  pinConfigure(IN2, PIN_DIR_OUTPUT);      // IN2
  pinConfigure(PWM1, PIN_DIR_OUTPUT);      // PWM

  // Motor off
  digitalWrite(IN1, LOW); 
  digitalWrite(IN2, LOW);
    
  // In order to configure a pin as an input, for example the button SW0 at
  // PD2, we can do the following:
  pinConfigure(PIN_PD2, PIN_DIR_INPUT | PIN_PULLUP_ON);

  // Then we can e.g. attach an interrupt to the button when it is pressed (on
  // the falling edge). If we want to have an interrupt when the button is
  // released, we'd need to use the rising edge instead.
  //
  // We could also use digitalRead(PIN_PD2) in a loop in order to check the
  // value continuously
  attachInterrupt(PIN_PD2, buttonInterrupt, FALLING);

  // We start the Serial3, which is used to print messages. As one can also
  // see on the same page in the hardware user guide, the USART3 is used for
  // sending messages to the debugger, which again is connected to the
  // computer via USB. We thus have to be careful to use Serial3 and not
  // Serial for printing
  Serial3.begin(115200);
  Serial3.println("Press SW0 for increasing the duty cycle up to 250");
}

void loop(){
  // Motor ON
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(PWM1, dutyCycle);
  
  if (button_pressed)
  {
    Serial3.println(F("Button pressed"));
    dutyCycle = dutyCycle + 10;
    if (dutyCycle > 255)
      dutyCycle = 60;           // Lowest dutycycle that activates the motor
    button_pressed = false;
    Serial3.println(dutyCycle);
  }
}

Credits

Alejandro Butron

Alejandro Butron

1 project • 1 follower

Comments