i am having trouble with driving motors with sabertooth 2x32.
I was working with Arduino between G431rb and Sabertooth 2x32. Everything is working well but not stable. I decided to remove Arduino but couldn"t handle communication between Sabertooh 2x32 and G431rb.
I checked the signals are going to the driver from arduino on the Hercules dekstop app. I tried to send these with USART but i didnt get any response.
uint8_t openRightSS[5] = {0x31, 0x32, 0x30, 0x0D, 0x0A};
// i got these hex numbers from hercules, when they sent to motor driver, motor driver works
HAL_UART_Transmit(&huart3, openRightSS,5,100);
I have some sources from Dimension Engineering(for Sabertooth 2x32 packet serial communication) website. There are some informations about CRC and Checksum but i couldnt implement them also.
Last thing that i found was sending data with different way(?).
void driveForwardMotor1(uint8_t address, uint8_t speed)
{
HAL_UART_Transmit(&huart3, address, strlen(address), 1000);
HAL_UART_Transmit(&huart3, 0, 1, 1000);
HAL_UART_Transmit(&huart3, speed, strlen(speed), 1000);
HAL_UART_Transmit(&huart3, ((address + 0 + speed) & (0b01111111)), strlen((address + 0 + speed) & (0b01111111)), 1000);
}
void driveBackwardMotor1(uint8_t address, uint8_t speed)
{
HAL_UART_Transmit(&huart3, address, strlen(address), 1000);
HAL_UART_Transmit(&huart3, 1, 1, 1000);
HAL_UART_Transmit(&huart3, speed, strlen(speed), 1000);
HAL_UART_Transmit(&huart3, ((address + 1 + speed) & (0b01111111)), strlen((address + 1 + speed) & (0b01111111)), 1000);
}
void driveForwardMotor2(uint8_t address, uint8_t speed)
{
HAL_UART_Transmit(&huart3, address, strlen(address), 1000);
HAL_UART_Transmit(&huart3, 4, 1, 1000);
HAL_UART_Transmit(&huart3, speed, strlen(speed), 1000);
HAL_UART_Transmit(&huart3, ((address + 4 + speed) & (0b01111111)), strlen((address + 4 + speed) & (0b01111111)), 1000);
}
void driveBackwardMotor2(uint8_t address, uint8_t speed)
{
HAL_UART_Transmit(&huart3, address, strlen(address), 1000);
HAL_UART_Transmit(&huart3, 5, 1, 1000);
HAL_UART_Transmit(&huart3, speed, strlen(speed), 1000);
HAL_UART_Transmit(&huart3, ((address + 5 + speed) & (0b01111111)), strlen((address + 5 + speed) & (0b01111111)), 1000);
}
Solved the issue. Data i received from hercules were not working(idk why). I tried to see what arduino sent to sabertooth board through another arduino. They were different hex data arrays, i tried them with this code and it worked
while(counter<3){ HAL_UART_Transmit(&huart3, forward, strlen(forward), 100); counter++; }
Related
I am using the STM32F103C8T6. I use the ADC for multi-channel voltage acquisition, and a potentiometer to control the voltage change. I find that the ADC value changes fluctuate. Why?
This is part of my ADC code:
uint32_t ADC_Get_Average(uint8_t ch,uint8_t times)
{
ADC_ChannelConfTypeDef sConfig;
uint32_t value_sum=0;
uint8_t i;
switch(ch)
{
case 1:sConfig.Channel = ADC_CHANNEL_1;break;
case 2:sConfig.Channel = ADC_CHANNEL_2;break;
case 3:sConfig.Channel = ADC_CHANNEL_3;break;
}
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.Rank = 1;
HAL_ADC_ConfigChannel(&hadc1,&sConfig);
for(i=0;i<times;i++)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,5);
value_sum += HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
}
return value_sum/times;
}
void ADC_PROC(void)
{
ADC_value1 = ADC_Get_Average(1,5) / 4096.0 * 3.3;
ADC_value2 = ADC_Get_Average(2,5) / 4096.0 * 3.3;
ADC_value3 = ADC_Get_Average(3,5) / 4096.0 * 3.3;
sprintf(adcbuff1, "V1:%.2fV", ADC_value1);
oled_show_string(24, 0, adcbuff1, 2);
sprintf(adcbuff2, "V2:%.2fV", ADC_value2);
oled_show_string(24, 2, adcbuff2, 2);
sprintf(adcbuff3, "V3:%.2fV", ADC_value3);
oled_show_string(24, 4, adcbuff3, 2);
}
enter image description here
I have tried to change the length of ADC's acquisition cycle side, but the effect is still the same, with severe fluctuations.
I am trying to build a 3D FPS game in unity. A friend of mine bought a (replica) gun and modified it to add an ESP32 and an MPU-9250 gyroscope/accelerometer in it to track and send the rotation of the gun (using quaternions) to unity. The problem is that each time I "power on" the gun and start the game the initial rotation of the weapon in the game is different. (I don't want to use euler angles because of the gimbal lock problem.) Any ideas where the problem might be and how to fix it?
I am currently using the MPU-9250 DMP Arduino Library as in here.
I have started thinking that the problem lies on the fact that each time I turn on the power of the gun, the gyroscope axes are reinitialized. According to another library - Calibration - accel/gyro/mag offsets are NOT stored to register if the MPU has powered off. You need to set all offsets at every bootup by yourself (or calibrate at every bootup). I do not want to do that every time the ESP32 is restarted. If only I could use a fixed coordinate system no matter what the position of the gun is, when the ESP32 reboots.
Here is the code I have written so far:
#include "src\lib\SparkFunMPU9250-DMP.h"
#include <WiFi.h>
#include <WiFiUdp.h>
// -------------------------------------------------------------------------------------------
// Enter: WEAPON_* OR Handgun_*
const String gun = "Handgun_4";
char * udpAddress;
int udpPort;
int Trigger;
int Mag;
int Shutter;
// -------------------------------------------------------------------------------------------
// --- Trigger ---
//const int Trigger = 4;
int button_state_trigger = 0;
int button_state_mag = 0;
int button_state_shutter = 0;
// --- MPU9250 ---
MPU9250_DMP imu;
// --- WiFi ---
WiFiUDP udp;
// WIFI credentials
const char * networkName = "...";
const char * networkPswd = "...";
// IP address to send UDP data to:
// either use the ip address of the server or
// a network broadcast address
//const char * udpAddress = ...;
// UDP port
//const int udpPort = ...;
// payload to sent
String payload = "";
//Connection state?
boolean connected = false;
// Timers
unsigned long timer1, timer2;
// -------------------------------------------------------------------------------------------
void setup() {
GunSelect(gun);
// Initialize Serial Com
Serial.begin(115200);
// Initialize Trigger
pinMode(Trigger, INPUT);
pinMode(Mag, INPUT);
pinMode(Shutter, INPUT);
// Initialize MPU9250
while (imu.begin() != INV_SUCCESS) {
Serial.println("Unable to communicate with MPU-9250");
delay(2000);
}
imu.setSensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS); // Enable all sensors
imu.setGyroFSR(2000); // Set Gyro dps, options are +/- 250, 500, 1000, or 2000 dps
imu.setAccelFSR(16); // Set Accel g, options are +/- 2, 4, 8, or 16 g
imu.setSampleRate(100); // Set sample rate of Accel/Gyro, range between 4Hz-1kHz
imu.setLPF(5); // Set LPF corner frequency of Accel/Gyro, acceptable cvalues are 188, 98, 42, 20, 10, 5 (Hz)
imu.setCompassSampleRate(100); // Set Mag rate, range between: 1-100Hz
imu.dmpBegin(DMP_FEATURE_6X_LP_QUAT | // 6-axis (accel/gyro) quaternion calculation
DMP_FEATURE_GYRO_CAL , // Gyroscope calibration (0's out after 8 seconds of no motion)
200);
delay(10000);
// Initialize WiFi
connectToWiFi(networkName, networkPswd);
}
// -------------------------------------------------------------------------------------------
void loop() {
// Timer Start
// timer1 = micros();
if ( imu.fifoAvailable() ) {
if ( imu.dmpUpdateFifo() == INV_SUCCESS ) {
// Switches Read
button_state_trigger = buttonState(Trigger);
if (gun == "WEAPON_1" || gun == "WEAPON_2" || gun == "WEAPON_3" || gun == "WEAPON_4" || gun == "WEAPON_5" || gun == "WEAPON_Test") {
button_state_mag = buttonState(Mag);
button_state_shutter = buttonState(Shutter);
}
double x = imu.calcQuat(imu.qx);
double y = imu.calcQuat(imu.qy);
double z = imu.calcQuat(imu.qz);
double w = imu.calcQuat(imu.qw);
Serial.println();
Serial.println(button_state_trigger);
Serial.println(button_state_mag);
Serial.println(button_state_shutter);
Serial.println("x: " + String(x));
Serial.println("y: " + String(y));
Serial.println("z: " + String(z));
Serial.println("w: " + String(w));
Serial.println();
//*/
// Send data via WiFi
payload = "ACC|" + String(x,4) + "|" + String(y,4) + "|" + String(z,4) + "|" + String(w,4) + "|" + String(button_state_trigger) + "|" + String(button_state_mag) + "|" + String(button_state_shutter);
sendData(payload);
}
}
// Timer End
// timer2 = micros();
// Serial.println(timer2 - timer1);
}
In Unity I receive the data and parse it as 4 floats. Then I set the gun's rotation in the game as (y,w,-x,z) because the coordinate system of the gun is different from the one that Unity uses. So the code is like:
// Receiving data...
float x = float.Parse(data[1]);
float y = float.Parse(data[2]);
float z = float.Parse(data[3]);
float w = float.Parse(data[4]);
gun.rotation = new Quaternion(y,w,-x,z);
----------------Edit--------------------
I read about Madgwick filter (alternatively Kalman filter and Mahony filter) which is said to be able to produce a quaternion-based estimate of absolute device orientation (based on the earth's reference system ie. North etc.) If I understood correctly . But I am not really sure if that solves my problem.
I'm not able to understand the use of VREFINT in stm32f103 board. Can anyone explain me how to get adc value in stm32f103 using VREFINT?
if(HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
{
adcVrefInt = HAL_ADC_GetValue(&hadc1);
vdd = 4095.0 * 1.20 / (float)adcVrefInt;
vdd += 0.61; // .61 is the difference i'm getting in VDD
sprintf(buffer, "VREFINT: %ld\tVDD: %.2f\t", adcVrefInt, vdd);
HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), 100);
if(HAL_ADC_PollForConversion(&hadc2, 100) == HAL_OK)
{
adcValue = HAL_ADC_GetValue(&hadc2);
adcVoltage = (vdd/4095.0) * adcValue;
sprintf(buffer, "ADC_PA0: %ld\tVoltage-PA0: %.2f\n", adcValue, adcVoltage);
HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), 100);
}
}
You can read the VREFINT channel (17) much like any other channel on ADC1, after setting the TSVREFE bit in ADC1->CR2. It's an internal analog signal, there is no pin associated with it. VREFINT has a fixed voltage of 1.20 ± 0.04 V.
If an ADC input pin is connected to VDDA, you get a reading of 4095. If it's connected to VSSA, you get 0. If there is any other voltage V1 between these limits, you get 4095 * V1 / VDDA. This applies to the VREFINT channel as well.
When you measure VREFINT, ADC1->DR = 4095 * VREFINT / VDDA. Because you know that VREFINT = 1.20V, you can calculate VDDA=4095 * 1.20 / ADC1->DR Volts.
I am using a pressure sensor D6F-PH to measure the pressure difference. This is my Arduino code that I wrote to get the values from the sensor.
#include "Wire.h"
#define addrs 0x6C // I2C bus address
int P;
int I;
float T;c
int initialize(int i2c_addr)
{
//INITIALIZATION AFTER POWER UP
Wire.beginTransmission(i2c_addr);
Wire.write(0x0B);
Wire.write(0x00);
int x = Wire.endTransmission();
return x;
}
int pressure(int i2c_addr)
{
//MCU MODE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0); // reg 0 - address register high byte
// Wire.write(0x51); // reg 1 - address register low byte
Wire.write(0x40); // reg 1 - address register low byte
Wire.write(0x18); // reg 2 - serial control register - indicate # bytes among others (page 7 bottom)
Wire.write(0x06); // reg 3 - value to be written to SENS control register
int x = Wire.endTransmission();
delay(33);
//WRITE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0);
Wire.write(0x51);
Wire.write(0x2C);
x = Wire.endTransmission();
//READ
Wire.beginTransmission(i2c_addr);
Wire.write(0x07);
x = Wire.endTransmission();
Wire.requestFrom(i2c_addr, 2);
byte hibyte = Wire.read();
byte lobyte = Wire.read();
long raw = word( hibyte, lobyte);
//Serial.print("raw pressure:\t ");
Serial.println(raw);
// D6F-PH5050AD3 ==> rangeMode=500 ==> int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode
// D6F-PH0505AD3 ==> rangeMode=50 ==> int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode
// D6F-PH0025AD1 ==> rangeMode=250 ==> int rd_pressure=(raw - 1024) * rangeMode / 60000L
//int rangeMode = 50;
int rangeMode = 250;
int rd_pressure = (raw - 1024) * rangeMode / 60000L;
//int rd_pressure = ((raw - 1024) * rangeMode * 10/60000L) - rangeMode;
return rd_pressure;
}
float temperature(int i2c_addr)
{
//MCU MODE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0); // reg 0 - address register high byte
// Wire.write(0x51); // reg 1 - address register low byte
Wire.write(0x40); // reg 1 - address register low byte
Wire.write(0x18); // reg 2 - serial control register - indicate # bytes among others (page 7 bottom)
Wire.write(0x06); // reg 3 - value to be written to SENS control register
int x = Wire.endTransmission();
delay(33);
//WRITE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0);
Wire.write(0x61);
Wire.write(0x2C);
x = Wire.endTransmission();
//READ
Wire.beginTransmission(i2c_addr);
Wire.write(0x07);
x = Wire.endTransmission();
Wire.requestFrom(i2c_addr, 2);
byte hibyte = Wire.read();
byte lobyte = Wire.read();
long raw = word( hibyte, lobyte);
//Serial.print("raw temperature:\t ");
//Serial.println(raw);
int temp = round((float)(raw - 10214) / 3.739); // this is the temperature multiplied by 10...
return (temp / 10.0); // ...and the function returs the float
temperature with 0.1°C resolution
}
void setup()
{ // Open serial communications
Wire.begin();
Serial.begin(9600);
I = initialize (addrs); // start wire connection
}
void loop()
{
P = pressure(addrs);
Serial.print("pressure:\t ");
Serial.println(P);
T = temperature(addrs);
Serial.print("temperature:\t ");
Serial.println(T);
delay(300); //delay for 30 seconds
}
I can measure the pressure and the temperature from the arduino uno board using the Serial Monitor.
When I try to Retrieve the data using MATLAB I am unable to do so.
s=serial('COM6','BaudRate',9600);
fopen(s);
This is the error message that I get when I try to open the port : Error using serial/fopen (line 72)
Open failed: Cannot connect to the COM2 port. Possible reasons are another
application is connected to the port or the port does not exist.
I have checked the COM port number and also used the delete(instrfindall); command but to no avail.
Please help
Resolved. I needed to close the Serial Monitor before creating a connection with MATLAB.
I have the following problem that can't get my head around.
I have the following method (used in an embedded platform) that uses select():
int wait_fd_readable(int fd, long msec)
{
fd_set rset;
FD_ZERO(&rset);
FD_SET(fd, &rset);
struct timeval tv = { msec / 1000, (msec % 1000) * 1000 };
struct timeval *timeout = msec < 0 ? 0 : &tv;
return select(fd + 1, &rset, 0, 0, timeout);
}
It works very well in general, except when I disconnect the network cable where select seems to hang and never return -1 as expected.
Does anyone have any tip on why might that be?
Your problem seems to be in struct timeval *timeout = msec < 0 ? 0 : &tv; line:
If msec is negative, timeout is set to NULL, and your select call will wait infinitly.
From man select:
If timeout is NULL (no timeout), select() can block indefinitely.
Try to replace with:
int wait_fd_readable(int fd, long msec)
{
fd_set rset;
FD_ZERO(&rset);
FD_SET(fd, &rset);
if (msec < 0) {msec = 0;}
struct timeval tv = { msec / 1000, (msec % 1000) * 1000 };
return select(fd + 1, &rset, 0, 0, &tv);
}