How to Generate PWM with delay? - microcontroller

I am implementing an isolated boost converter. I have to generate a PWM signal for the switches given in the figure below. I have difficulty understanding the pattern. The PWM pattern is as follows: At the beginning all four switches are kept on, then switches 1, 4 are kept on while switches 2, 3 are closed as shown in the figure. Please, help me to get started on this problem. How can I generate this type of PWM? Then, at a later time the PWM should be shifted with some duty cycle time for Q2, Q3. I am confused. How can I add some delay or shift the PWM? I am using a pic18f45k22 micro controller, and the programming tool is MikroC.

I don't know whether the length of the "off" time is critical, but suppose the mark/space ratio is 1:3 as suggested in your timing diagram,
Q1,Q4 1011101110111
Q2,Q3 1110111011101
Configure a free-run timer to interrupt at one quarter of your required cycle period. At each interrupt it performs one of four tasks in sequence, such as this pseudo code
void timer_interrupt() {
static int operation = 0; // is initialised only once
clear_timer_status(); // acknowledge the interrupt
switch (operation) {
case 0: Q14_off();
break;
case 1: Q14_on();
break;
case 2: Q23_off();
break;
case 3: Q23_on();
break;
}
operation = (operation + 1) % 4; // advance to next operation
}
If you want a smaller mark/space ratio, you can do it in a similar way. Suppose you want a ratio of 1:7 represented by
Q1,Q4 101111111011111110
Q2,Q3 111110111111101111
now in this case the timer rate should be one eighth of the cycle, but not every interrupt will have an action
void timer_interrupt() {
static int operation = 0; // is initialised only once
clear_timer_status(); // acknowledge the interrupt
switch (operation) {
case 0: Q14_off();
break;
case 1: Q14_on();
break;
case 4: Q23_off();
break;
case 5: Q23_on();
break;
}
operation = (operation + 1) % 8; // advance to next operation
}
There are other ways to do this: such as an array of output bit patterns that you look up as pattern[operation]

Related

Why does the IR reciver gives diffrent value everytime I try to break a for loop - when new value is recived, Arduino ide?

I am new to Arduino programming and was trying to make an IR-controlled WS2812 led strip light, everything works fine apart from when I try to stop the for-loop when my IR receiver gets a new decoded value. It does get the job done but the received values are different every time. when I tested the same controller with a simple IR receiver program everything worked fine.
switch(value){
case 16720095:
delay (200);
irrecv.resume();
for (int i = 0; i <= 182; i++) {
leds[i] = CRGB (0,0,0);
FastLED.show();
if (irrecv.decode(&results))
{
value = results.value;
Serial.println(value);
break;
}
delay(40);
}
}
}
and the serial outputs:
first time:
16720095
-1572362453
second time:
16720095
-1406992986
third time:
16720095
811035822
It looks like you need to call "irrecv.resume()" within the if (irrecv.decode(&results)) block in order to tell the driver to keep looking for signals. The second values you are getting are garbage because you are asking it to provide data it hasn't received/ prepared.

How to control the speed of a stepper motor using PID control and ultrasonic sensor?

Little backstory:
I'm currently doing this project that deals with using two cars, called block A and B, which block B has to maintain a distance of 10 cm from block A using PID, PD, PI, or P. I'm using a PID. Block B uses an Arduino whereas Block A is controlled by the user by hand. Block B uses a unipolar stepper motor as the actuator and an ultrasonic sensor to sense the distance. My professor wants the motor to move in both directions and have varying speeds (slow, medium, and fast). I'm using brett's PID since I have used it before in my previous labs.
Problem:
I have an issue with how to create varying speeds for block B like intuitively I know that I want the B should move for example, fast if the car is greater than 20 cm, medium if the car is between 20cm and 14cm, and slow if it's between 14cm and 10cm. But I just can't use the input value retrieved from the sensor directly to control the motor as it would make it an open system. So I used the error retrieved from Brett's PID code to control the stepper motor. So far, I have gotten the directions to work by setting the myPID.SetOutputLimits(-800,800);. But as it tried to use the error to control the speed it would be impossible because the error always fluctuates at a specific distance. For example at 12cm, I would get either 800 or around 300. I'm currently confused about how to implement control of the speed of my stepper motor through PID and any help regarding this issue will be appreciated.
Code:
Code was through Arduino IDE.
#include "SR04.h"
#include <Stepper.h>
#include <PID_v1.h>
#define TRIG_PIN 7
#define ECHO_PIN 6
//intialization of Ultrasonic sensor
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long s;
//intializing motor variables
int stepsPerRevolution = 2048;
int motorSpeed = 6;
Stepper myStepper (stepsPerRevolution, 8, 10, 9, 11);
//Declared PID variables
double Setpoint = 10; //desired temp value
double Input; //thermsitor
double Output; //DC motor
double Error;
//defined variables for PID parameters
double Kp=100, Ki=10, Kd=1;
//PID equation
PID myPID(&Input, &Output, &Setpoint, Kp, Kd, Ki, REVERSE);
void setup(){
Serial.begin(9600);
//setting PID
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-800,800);
//speed intialized
myStepper.setSpeed(motorSpeed);
}
void loop(){
s=sr04.Distance();
Input = s;
myPID.Compute();
Error = Input - Setpoint;
//Serial.print(Input);
//Serial.print(",");
//Serial.println(Setpoint);
Serial.println(Output);
//Serial.print(",");
//Serial.println(Error);
Error = Output;
//Away from Block B
if (0<Error<800){
myStepper.setSpeed(motorSpeed);
myStepper.step(-300);
} //slow speed
if (Error>=800){
myStepper.setSpeed(motorSpeed*2);
myStepper.step(-128);
} //fast speed
//Towards Block B
if (-800<Error<0) {
myStepper.setSpeed(motorSpeed);
myStepper.step(128);
} //slow speed
if (Error<=-800) {
myStepper.setSpeed(motorSpeed*2);
myStepper.step(128);
}//Fast speed
}
What you need to do is calcuulate how much you need to change your current speed to minimize the error in distance.
Your calculation for error is not in the right place.
void loop()
{
long s=sr04.Distance();
Input = s; // using global variables to pass values to your PID
// is not a good idea. Use function parameters instead.
// You are storing a 32 bit value in a 16 bit variable!!!
// That's only the start of your problems.
myPID.Compute();
Error = Input - Setpoint; //
Since we're starting with a major design flaw, I'll have to assume you'll fix that and change your PID code to accept and compute long integers both as input value as a function parameter, and as the type of its return value..
What you want to do is compute the PID from the error in distance from your set point, and then modulate the current speed accordingly. PIDs work best when used directly, using 7 speeds (1 stopped, 3 forward/3 backwards) is possible, but I don't think it'll give better results, I'll leave the exercise to you.
I haven't tried this, I don't have any cars on hand. This is a skeletoon of how I'd go about it. Tuning the PID should be what takes you the longest.
//...
// speeds are in RPMs.
long curSpeed = 0;
const long MAX_SPEED = XXX; // whatever you max speed is for your car.
const long MIN_NEG_SPEED = -XXX; // whatever you max speed is for your car going reverse.
const long MIN_SPEED = XXX; // below this absolute speed, we're stopped.
const int SLICE_TIME = 10; // time between readings and adjustments, in ms.
// you'll need to adjust this according to you minimum speed, and steps per turn.
const long STEPS_PER_TURN = 200; // change to whatever you steps/turn value is.
// you'll need to limit the output of your PID to match the acceleration your
// motors can handle for your particular car.
// returns the number of steps to run for our slice time.
long Steps(int speed)
{
if (-MIN_SPEED <= speed && speed <= MIN_SPEED)
return 0;
// compute number of steps for our slice time.
// choose slice time and minimum speed wisely!!
long steps = (SLICE_TIME * (speed * STEPS_PER_TURN)) / (60000L);
// for very low speeds. I've added this, because I'm unsure of the
// time domain behaviour of stepper library with less than 2 steps
if (-1 <= steps && steps <= 1)
{
if (speed < 0)
return -2;
else
return 2;
}
return int(steps);
}
void loop()
{
// You may want to filter the sr04 readings with a median of 5
// filter to limit input noise.
// You want to keep the car at a distance of 'set_point'
// from the leading car. distance_error is the error you want to
// minimize to zero by using the PID, and that's what should be
// the PID input.
//
// The way this works. We are rolling at speed curSpeed, we
// measure the error in distance from our set_point, feed that
// to the PID, then accelerate or decelerate by subtracting
// the output of the PID from the current speed.
//
// Note: you can add or subtract the PID to/from the current speed,
// the sign of the PID depends on you coefficients and sensor.
// I've used subtraction here because that's how you express
// negative feedback mathematically. In real life, we'll use what
// best fits our needs. Usually it's the operation that makes P
// positive.
long distance_error = sr04.Distance() - setPoint;
long pid_out = myPID.Compute(distance_error);
// increment or decrement the current speed to try and reduce the error.
long speed = curSpeed - pid_out; // As usual, PID coefficients do matter
// for this to work well.
if (speed > MAX_SPEED)
speed = MAX_SPEED;
if (speed < MIN_NEG_SPEED)
speed = MIN_NEG_SPEED;
curSpeed = speed;
if (speed < 0)
speed = -speed;
myStepper.setSpeed(speed); // modulate speed
int steps = Steps(curSpeed);
if (steps)
myStepper.step(steps); // keep rolling.
}
I haven't tried to compile it either, so this may not compile as is. But most of the tricks and traps are covered, and this should give you a head start, if you want to go the PID route. But I think your professor will really wonder where that one came from :) Still, you should try and make it run, for fun.
The other way, without a PID, and using set speeds is much more straightforward. It may also be closer to what the is required by the exercise. The distance between cars will vary a bit more, of course. And it does not use a PID at all.
const int MAX_SPEED = 3;
int speed = 0; // value range is [-MAX_SPEED, +MAX_SPEED]
long RPMS[MAX_SPEED + 1] = { 0, 200, 400, 800 }; // in RPMs, assuming average speed will be around 400, in this case.
// For 3 speeds, the difference between speeds cannot be higher than max acceleration.
// You can add as many speeds as desired. More speeds = more precision.
const long STEPS_PER_TURN = 200; // change to whatever you steps/turn value is. MUST be 200 or more.
const int STEPS = STEPS_PER_TURN / 100; // 3.6° between speed adjustment.
// it is very small right now, so
// you will want to play with this value.
// this threshold gives some control over aceleration.
// and 'hardness' of distance tracking.
const long THRESHOLD = 0;
void loop()
{
// get the error in distance.
long distance_error = sr04.Distance() - setPoint;
// modulate speed.
if (distance_error > THRESHOLD)
++speed;
if (distance_error < -THRESHOLD)
--speed;
if (speed > MAX_SPEED)
speed = MAX_SPEED;
if (speed < -MAX_SPEED)
speed = -MAX_SPEED;
long rpm = RPMS[(speed < 0) : -speed : speed];
if (rpm)
{
myStepper.setSpeed(rpm);
myStepper.setSpeed((speed < 0) ? -STEPS : STEPS)
}
}
For this code, you must choose speeds and STEPS value that will give you an acceleration without misssed steps.

Changing ns2 code for MAC 802_3 to turn off collission detection

I've been working on ns2 simulations for the past few weeks and need to change the implementation in ns-2.35/mac/mac-802_3.cc to turn off collision detection.
This is the code that runs whenever a collision takes place -
void Mac802_3::collision(Packet *p) {
PRNT_MAC_FUNCS(this);
if (mhIFS_.busy()) mhIFS_.cancel();
double ifstime= netif_->txtime(int((IEEE_8023_JAMSIZE+IEEE_8023_IFS_BITS)/8.0)); //jam time + ifs
mhIFS_.schedule(ifstime);
switch(state_) {
case MAC_SEND:
// If mac trace feature is on generate a collision trace for this packet.
if (trace_)
drop(p);
else
Packet::free(p);
if (mhSend_.busy()) mhSend_.cancel();
if (!mhRetx_.busy()) {
/* schedule retransmissions */
if (!mhRetx_.schedule(ifstime)) {
p= mhRetx_.packet();
hdr_cmn *th = hdr_cmn::access(p);
HDR_CMN(p)->size() -= (ETHER_HDR_LEN + HDR_MAC(p)->padding_);
fprintf(stderr,"BEB limit exceeded:Dropping packet %d\n",th->uid());
fflush(stderr);
drop(p); // drop if backed off far enough
mhRetx_.reset();
}
}
break;
case MAC_RECV:
Packet::free(p);
// more than 2 packets collisions possible
if (mhRecv_.busy()) mhRecv_.cancel();
break;
default:
assert("SHOULD NEVER HAPPEN" == 0);
}
}
I've tried commenting the .cancel() part to avoid cancelling the transmission when collision is detected. But this does not work as expected and I get zero throughput on the network. Can someone guide me on how I can achieve this ?

Arduino Function Execution Time

I have an Arduino and an APC220 wireless transceiver. I'm writing a library that reads in data from the APC using the SoftwareSerial class. I originally started with the (incorrect) code below that was causing a seg fault because the i variable is incremented even when there is no data available to read. In cases where it happened to work (by chance when the data was immediately available), this function took approximately 6 milliseconds to execute. When I put the i++; statement in its proper place (above the closing brace immediately above it), the function takes over 270 ms to run. Speed is crucial for this function, so I'm wondering what it is about that statement's placement that causes such a dramatic increase in time.
For the code below, buff is declared as char buff[10]; and sSerial is an instance of SoftwareSerial
unsigned long updateLocation(Marker* marker) {
this->sSerial->print('~');
//initiate request from vision system
this->sSerial->flush();
this->sSerial->print('#');
this->sSerial->print(marker->num);
this->sSerial->print('*');
this->sSerial->flush();
unsigned long start = millis();
int state = 0, i = 0;
while((millis() - start) < 600) {
if(this->sSerial->available()) {
buff[i] = this->sSerial->read();
if(buff[i] == ',') {
buff[i] = 0;
switch(state) {
case 0:
i = -1;
state++;
break;
case 1:
marker->x = atof(buff);
i = -1;
state++;
break;
case 2:
marker->y = atof(buff);
i = -1;
state++;
break;
case 3:
marker->theta = atof(buff);
i = -1;
return (millis() - start);
break;
default:
return 0;
break;
}
}
// Correct location for i++; takes 270 ms to execute
}
// Incorrect location for i++; Takes 6 ms to execute
i++;
}
this->sSerial->print('~');
this->sSerial->flush();
return 0;
}
Assuming that there's data ready and waiting from sSerial, there's no effective difference in the placement of i++.
You said yourself, in most cases the data isn't ready. With the incorrect placement of i++, i quickly grows to greater than the size of buff which causes the segfault.
With the correct placement, your code blocks for up to 600ms waiting for enough data to come in to reach case 3 and return. On average, you're seeing that it takes 270ms for that to happen.
You can test this theory yourself by timing the same function operating directly on a string rather than reading in from serial.
You may want to a) increase your baud rate b) check to see if there's a more efficient software serial implementation you can use c) switch to hardware serial. If you are only using hardware serial currently for debugging output, you can switch that around. Use an FTDI adapter ($6-10 on eBay) to pipe software serial to USB and reserve the hardware serial for your time sensitive function.
You might also be able to reconfigure your code so it doesn't block the whole time waiting. You can read in what's available, store it in a global and go back to your main loop to do something else until there's data available again.
edit: I see now that the APC220 is 9600 baud max. That's pretty slow, so the bottle neck may not be software serial (but you should test it). If the bottle neck is simply the baud rate, you will need to look at optimizing your code not to block waiting for input if there are other things your system can work on while it's waiting.

Calculating the average of Sensor Data (Capacitive Sensor)

So I am starting to mess around with Capacitive sensors and all because its some pretty cool stuff.
I have followed some tutorials online about how to set it up and use the CapSense library for Arduino and I just had a quick question about this code i wrote here to get the average for that data.
void loop() {
long AvrNum;
int counter = 0;
AvrNum += cs_4_2.capacitiveSensor(30);
counter++;
if (counter = 10) {
long AvrCap = AvrNum/10;
Serial.println(AvrCap);
counter = 0;
}
}
This is my loop statement and in the Serial it seems like its working but the numbers just look suspiciously low to me. I'm using a 10M resistor (brown, black, black, green, brown) and am touching a piece of foil that both the send and receive pins are attached to (electrical tape) and am getting numbers around about 650, give or take 30.
Basically I'm asking if this code looks right and if these numbers make sense...?
The language used in the Arduino environment is really just an unenforced subset of C++ with the main() function hidden inside the framework code supplied by the IDE. Your code is a module that will be compiled and linked to the framework. When the framework starts running it first initializes itself then your module by calling the function setup(). Once initialized, the framework enters an infinite loop, calling your modules function loop() on each iteration.
Your code is using local variables in loop() and expecting that they will hold their values from call to call. While this might happen in practice (and likely does since that part of framework's main() is probably just while(1) loop();), this is invoking the demons of Undefined Behavior. C++ does not make any promises about the value of an uninitialized variable, and even reading it can cause anything to happen. Even apparently working.
To fix this, the accumulator AvrNum and the counter must be stored somewhere other than on loop()'s stack. They could be declared static, or moved to the module outside. Outside is better IMHO, especially in the constrained Arduino environment.
You also need to clear the accumulator after you finish an average. This is the simplest form of an averaging filter, where you sum up fixed length blocks of N samples, and then use that average each Nth sample.
I believe this fragment (untested) will work for you:
long AvrNum;
int counter;
void setup() {
AvrNum = 0;
counter = 0;
}
void loop() {
AvrNum += cs_4_2.capacitiveSensor(30);
counter++;
if (counter == 10) {
long AvrCap = AvrNum/10;
Serial.println(AvrCap);
counter = 0;
AvrNum = 0;
}
}
I provided a setup(), although it is redundant with the C++ language's guarantee that the global variables begin life initialized to 0.
your line if (counter = 10) is invalid. It should be if (counter == 10)
The first sets counter to 10 and will (of course) evaluate to true.
The second tests for counter equal to 10 and will not evaluate to true until counter is, indeed, equal to 10.
Also, kaylum mentions the other problem, no initialization of AvrNum
This is What I ended up coming up with after spending some more time on it. After some manual calc it gets all the data.
long AvrArray [9];
for(int x = 0; x <= 10; x++){
if(x == 10){
long AvrMes = (AvrArray[0] + AvrArray[1] + AvrArray[2] + AvrArray[3] + AvrArray[4] + AvrArray[5] + AvrArray[6] + AvrArray[7] + AvrArray[8] + AvrArray[9]);
long AvrCap = AvrMes/x;
Serial.print("\t");
Serial.println(AvrCap);
x = 0;
}
AvrArray[x] = cs_4_2.capacitiveSensor(30);
Serial.println(AvrArray[x]);
delay(500);

Resources