Модераторы: Death_Morozz, null, Ale
DmRaF писал(а):А против писка моторов использую наушники
/*
Arduino code for dynamic playseat 2DOF
Created 24 May 2011 by Jim Lindblom SparkFun Electronics https://www.sparkfun.com/products/10182 "Example Code"
Created 24 Apr 2012 by Jean David SEDRUE Version betatest26 - 24042012 http://www.gamoover.net/Forums/index.php?topic=25907
Updated 20 May 2013 by Mathieu RIVIER in english http://www.xsimulator.net/2dof-wiper-motor-playseat/ in french : http://www.gamoover.net/Forums/index.php?topic=27617
Updated 30 April 2014 by RacingMat (bug for value below 16 corrected)
Updated 1 June 2014 by RacingMat: implementation of Ultrasonic PWM (don't stack the motomonster! follow the new pinout!)
results in video here : https://www.youtube.com/watch?v=FzhUga64fJs
*/
#define BRAKEVCC 0
#define RV 2 //beware it's depending on your hardware wiring
#define FW 1 //beware it's depending on your hardware wiring
#define STOP 0
#define BRAKEGND 3
////////////////////////////////////////////////////////////////////////////////
#define pwmMax 255 // or less than 255, if you want to lower the maximum motor's speed
#define pwmMini 150
// defining the range of potentiometer's rotation 0 <-> 1024
const int potMini=200;
const int potMaxi=800;
////////////////////////////////////////////////////////////////////////////////
#define motLeft 1
#define motRight 0
#define potL A0
#define potR A1
////////////////////////////////////////////////////////////////////////////////
// DECLARATIONS
////////////////////////////////////////////////////////////////////////////////
/* VNH2SP30 pin definitions
// with 20kHz PWM pinout is changed, you CANNOT stack the motomonster anymore!
Arduino /..Motomonster1
......GND <-> GND pin
........5V <-> 5V
.....pin 4 <-> pin 4 inA motor1
.....pin 5 <-> pin 9 inB motor2
.....pin 6 <-> xxxx
.....pin 7 <-> pin 7 inA motor2
.....pin 8 <-> pin 8 inB motor1
.....pin 9 <-> pin 5 pwm motor1
.....pin 10 <-> pin 6 pwm motor2 */
int inApin[2] = {
7, 4}; // INA: Clockwise input
int inBpin[2] = {
8, 5}; // INB: Counter-clockwise input
int pwmpin[2] = {
9, 10}; // PWM input
/* init position value at startup */
int DataValueL=512; //middle position 0-1024
int DataValueR=512; //middle position 0-1024
int sensorL,sensorR;
////////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
////////////////////////////////////////////////////////////////////////////////
void analogWriteSAH_Init( void )
{
// Stop the timer while we muck with it
TCCR1B = (0 << ICNC1) | (0 << ICES1) | (0 << WGM13) | (0 << WGM12) | (0 << CS12) | (0 << CS11) | (0 << CS10);
// Set the timer to mode 14...
//
// Mode WGM13 WGM12 WGM11 WGM10 Timer/Counter Mode of Operation TOP Update of OCR1x at TOV1 Flag Set on
// CTC1 PWM11 PWM10
// ---- ----- ----- ----- ----- ------------------------------- ---- ----------------------- -----------
// 14 1 1 1 0 Fast PWM ICR1 BOTTOM TOP
// Set output on Channel A and B to...
//
// COM1z1 COM1z0 Description
// ------ ------ -----------------------------------------------------------
// 1 0 Clear OC1A/OC1B on Compare Match (Set output to low level).
TCCR1A =
(1 << COM1A1) | (0 << COM1A0) | // COM1A1, COM1A0 = 1, 0
(1 << COM1B1) | (0 << COM1B0) |
(1 << WGM11) | (0 << WGM10); // WGM11, WGM10 = 1, 0
// Set TOP to...
//
// fclk_I/O = 16000000
// N = 1
// TOP = 799
//
// fOCnxPWM = fclk_I/O / (N * (1 + TOP))
// fOCnxPWM = 16000000 / (1 * (1 + 799))
// fOCnxPWM = 16000000 / 800
// fOCnxPWM = 20000
ICR1 = 799;
// Ensure the first slope is complete
TCNT1 = 0;
// Ensure Channel A and B start at zero / off
OCR1A = 0;
OCR1B = 0;
// We don't need no stinkin interrupts
TIMSK1 = (0 << ICIE1) | (0 << OCIE1B) | (0 << OCIE1A) | (0 << TOIE1);
// Ensure the Channel A and B pins are configured for output
DDRB |= (1 << DDB1);
DDRB |= (1 << DDB2);
// Start the timer...
//
// CS12 CS11 CS10 Description
// ---- ---- ---- ------------------------
// 0 0 1 clkI/O/1 (No prescaling)
TCCR1B =
(0 << ICNC1) | (0 << ICES1) |
(1 << WGM13) | (1 << WGM12) | // WGM13, WGM12 = 1, 1
(0 << CS12) | (0 << CS11) | (1 << CS10);
}
void analogWriteUltrasonic255( uint8_t motor, uint16_t value )
{
// My variable value varies from 0 to 255
// but awaited range in OCR1A is from 0 to 799 and nothing else!
switch (motor) {
case 0:
OCR1A=constrain(map(value, 0, 255, 0, 799), 0, 799); //D9
break;
case 1:
OCR1B=constrain(map(value, 0, 255, 0, 799), 0, 799); //D10
break;
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void setup()
{
analogWriteSAH_Init();
// serial initialization
Serial.begin(115200);
// initialization of Arduino's pins
for (int i=0; i<2; i++)
{
pinMode(inApin[i], OUTPUT);
pinMode(inBpin[i], OUTPUT);
pinMode(pwmpin[i], OUTPUT);
}
// Initialize braked for motor
for (int i=0; i<2; i++)
{
digitalWrite(inApin[i], LOW);
digitalWrite(inBpin[i], LOW);
}
}
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Main Loop ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void loop()
{
while (1==1) // to get the fastest loop possible
{
readSerialData(); // DataValueR & L contain the last order received (if there is no newer received, the last is kept)
// the previous order will still be used by the PID regulation MotorMotion Function
sensorR = analogRead(potR); // range 0-1024
sensorL = analogRead(potL); // range 0-1024
motorMotion(motRight,sensorR,DataValueR);
motorMotion(motLeft,sensorL,DataValueL);
}}
////////////////////////////////////////////////////////////////////////////////
// Procedure: wait for complete trame
////////////////////////////////////////////////////////////////////////////////
void readSerialData()
{
byte Data[3]={
'0','0','0' };
// keep this function short, because the loop has to be short to keep the control over the motors
if (Serial.available()>2){
//parse the buffer : test if the byte is the first of the order "R"
Data[0]=Serial.read();
if (Data[0]=='L'){
Data[1]=Serial.read();
Data[2]=Serial.read();
// call the function that converts the hexa in decimal and that maps the range
DataValueR=NormalizeData(Data);
}
if (Data[0]=='R'){
Data[1]=Serial.read();
Data[2]=Serial.read();
// call the function that converts the hexa in decimal and maps the range
DataValueL=NormalizeData(Data);
}
}
if (Serial.available()>16) Serial.flush();
}
////////////////////////////////////////////////////////
void motorMotion(int numMot,int actualPos,int targetPos)
////////////////////////////////////////////////////////
{
int Tol=20; // no order to move will be sent to the motor if the target is close to the actual position
// this prevents short jittering moves
//could be a parameter read from a pot on an analogic pin
// the highest value, the calmest the simulator would be (less moves)
int gap;
int pwm;
int brakingDistance=30;
// security concern : targetPos has to be within the mechanically authorized range
targetPos=constrain(targetPos,potMini+brakingDistance,potMaxi-brakingDistance);
gap=abs(targetPos-actualPos); // 0 <-> 1024
if (gap<= Tol) {
analogWriteUltrasonic255(numMot,0); //too near to move : stop -> pwm=0
}
else {
// PID : P only as it calculates speed according to distance
// smooth growing of speed
//pwm=pwmMini+((255-pwmMini)/(100-Tol))*(gap-Tol);
pwm=195;
if (gap>50) pwm=215;
if (gap>75) pwm=235;
if (gap>100) pwm=255;
pwm=map(pwm, 0, 255, 0, pwmMax); //adjust the value according to pwmMax for global sensitivity !
// if motor is outside from the range, send motor back to the limit !
// go forward (up)
if ((actualPos<potMini) || (actualPos<targetPos))
{
digitalWrite(inApin[numMot], HIGH);
digitalWrite(inBpin[numMot], LOW);
}
// go reverse (down)
if ((actualPos>potMaxi) || (actualPos>targetPos))
{
digitalWrite(inApin[numMot], LOW);
digitalWrite(inBpin[numMot], HIGH);
}
analogWriteUltrasonic255(numMot,pwm);
}
}
////////////////////////////////////////////////////////////////////////////////
// Function: convert Hex to Dec
////////////////////////////////////////////////////////////////////////////////
int NormalizeData(byte x[3])
////////////////////////////////////////////////////////////////////////////////
{
int result;
if ((x[2]==13) || (x[2]=='R') || (x[2]=='L')) //only a LSB and Carrier Return or 'L' or 'R' in case of value below 16 (ie one CHAR and not 2)
{
x[2]=x[1]; //move MSB to LSB
x[1]='0'; //clear MSB
}
for (int i=1; i<3; i++)
{
if (x[i]>47 && x[i]<58 ){//for xA to xF
x[i]=x[i]-48;
}
if ( x[i]>64 && x[i]<71 ){//for x0 to x9
x[i]=x[i]-55;
}
}
// map the range from game telemetry which is sent between (0 <-> 255) to the mechanically authorized range (potMini <-> potMaxi) (0<->1024)
result=map((x[1]*16+x[2]),0,255,potMini,potMaxi);
return result;
}
Да, тут не нулевой таймер используется, а первый. Он позволяет задать произвольную частоту, соответственно можно избавиться от писка. Но на Ардуино с такой прошивкой монстр не станет бутербродом - потребуются либо хардварные модификации, либо соединять соплями.lm890405 писал(а):вот прошивка которая не пищит
deadlymanager писал(а):Извиняюсь за глупый вопрос, можно ли подключить к ардуино с вашей прошивкой 86HSE8N BC38 Closed loop stepper motor, шаговик с энкодером.
#include <AccelStepper.h>
#define MOTOR1_DIR_PIN 3
#define MOTOR1_STEP_PIN 2
#define MOTOR1_ENABLE_PIN 4
#define MOTOR1_SPR 400 // Кол-во шагов на 1 оборот вала двигателя
int DataValueR=0; //middle position 0-255
int DataValueL=0;
AccelStepper stpMotor1(AccelStepper::DRIVER, MOTOR1_STEP_PIN, MOTOR1_DIR_PIN);
void setup()
{
Serial.begin(57600);
phInit();
}
void phInit()
{
pinMode(MOTOR1_DIR_PIN, OUTPUT);
pinMode(MOTOR1_STEP_PIN, OUTPUT);
stpMotor1.setAcceleration(10000);
stpMotor1.setMaxSpeed(100000);
stpMotor1.setCurrentPosition(DataValueR);
return;
}
////////////////////////////////////////////////////////////////////////////////
// Procedure: wait for complete trame
////////////////////////////////////////////////////////////////////////////////
void readSerialData()
{
char Data[3]={
'0','0','0' };
// keep this function short, because the loop has to be short to keep the control over the motors
if (Serial.available()>2){
//parse the buffer : test if the byte is the first of the order "R"
Data[0]=Serial.read();
if (Data[0]=='R'){
Data[1]=Serial.read();
Data[2]=Serial.read();
// call the function that converts the hexa in decimal and maps the range
DataValueR=hex_to_uchar(Data);
}
if (Data[0]=='L'){
Data[1]=Serial.read();
Data[2]=Serial.read();
// call the function that converts the hexa in decimal and maps the range
DataValueL=hex_to_uchar(Data);
}
}
if (Serial.available()>16) Serial.flush();
}
////////////////////////////////////////////////////////////////////////////////
// Function: convert Hex to Dec
////////////////////////////////////////////////////////////////////////////////
unsigned char hex_to_uchar(char x[3])
{
register unsigned char uc1,uc2;
uc1=(x[1] - '0');
if (uc1>9) uc1-=7;
uc2=(x[2] - '0');
if (uc2>9) uc2-=7;
return ((uc1<<4) | uc2 );
}
static char tab[] = "0123456789ABCDEF";
char *byte_to_hex(byte b)
{
char ss[3];
ss[0]= tab[b>>4];
ss[1]= tab[b & 0x0F];
ss[2]= 0;
return ss;
}
void loop() {
readSerialData();
stpMotor1.moveTo(DataValueR*20);
stpMotor1.run();
}
deadlymanager писал(а):Еще вопрос. Скажите люди знающие, где можно найти норм описание SimTools. Я уже башку сломал как ее настроить. Нормальной инструкции видимо в природе нет.
Death_Morozz писал(а):deadlymanager писал(а):Еще вопрос. Скажите люди знающие, где можно найти норм описание SimTools. Я уже башку сломал как ее настроить. Нормальной инструкции видимо в природе нет.
Ну на форуме же есть документация на русском!
Вернуться в X-SIMULATOR и RU-SIMULATOR & SimTools
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 48