hi i planning to made a multiple servo controlling with serial as control trigger signal on AVR with C and codevision
but when the trigger is true, the servo running in crazy loop, it back to original position (0 degree) instead of stay on desired position, my tutor give me hint to use "wait ... until" statement with the old data comparison but i'm not found the way to utilize it yet on google
because utilizing break; at the end of the if left the chip freeze until it reset
and the old code(it runs the servo forth and back continously)
while (1)
{
while(UCSRA & (1<<RXC))
{
// Place your code here
//data=UDR;
PORTC=UDR;
data=UDR;
//PORTB=data;
} ;
if (data== 0x0A || data== 0x0B)
{
if (data== 0x0A)
{
old_data=data;
PORTA=0x00;
PORTA.1=1;
movservo0(90,7);
movservo1(15,3);
}
if (data== 0x0B)
{
old_data=data;
PORTA=0x00;
PORTA.1=1;
movservo0(15,3);
movservo1(90,7);
}
}
}
as for movservo0 (another movservo() almost had same code)
void set_servo1(unchar derajat)
{ unchar n;
servo2=1;
delay_us(750);
for(n=0; n<derajat; n++)
{
delay_us(12);
};
servo2=0;
delay_ms(10);
}
void movservo0(unsigned char sudut, unsigned char speed)
{
unchar i;
set_servo1(sudut);
for (i=1;i<=sudut;i+=speed){
set_servo1(i);
delay_ms(100/speed);
}
}
This new code is a bit better.
The top of the while(UCSRA & (1<<RXC)) loop is fine this way. The loop body will only be entered if there is a character to be read. (Although, I'm not sure why you are expecting to read '\n' or vertical tab.)
A minor problem is the way the UDR is read. The act of reading UDR erases the contents. So you should be using
data=UDR;
PORTC=data;
The jumping of the servos appears to be in the moveservo() function. This function always sets the angle to 1 and then gradually increases the angle of the servo until it reaches the desired angle.
setservo() appears to be an attempt to perform PWM to drive a servo, but it doesn't work correctly. To keep the servo at a desired angle, you have to keep switching the pin from 0 to 1 at the correct times, not just once like this function does. Have you looked at the PWM functions of the timers? You just set these up and they run in the background. An alternative is to use a timer to set an interrupt to wake up and toggle the pins as you need.
If you want to do the switching of the pins without interrupts, then you should be using delays in the while(1) loop itself. Just use the setservo() functions to change some variables.
while(1)
{
// read the UART if ready and set the target values
// this part only runs occasionally
while(UCSRA & (1<<RXC))
{
// etc
}
// The rest of the loop body runs every time
// adjust the servo values toward the target values
// use a counter to determine if to adjust during this loop iteration
// e.g., a slow speed counts to a higher number before adjusting
delay(750);
for(int i = 0; i < NUM_INTERVALS; ++i)
{
// decide whether to set pins to 1 or 0 based on the servo values
delay(INTERVAL);
}
}
I don't know about your particular servos, but they typically have a period where most of the time the pin is 0, and then a short time in the period where the pin is 1. You will need to adjust NUM_INTERVALS and INTERVAL and 750 to add up to the correct length of time.
There is so much wrong with this snippet, it is hard to start. It is difficult to say why the servo is moving, as it is only ever "moved" to the same value every time. (Unless, you have omitted some code that sets it to some other value.)
Typically, when receiving UART, the processor should wait until the character is received. This is accomplished by this
while(UCSRA & (1<<RXC) == 0);
Note the ; creating an empty body of the while loop. This is probably what your tutor meant. When the flag is set, then the loop exits and the data is ready to be read.
while(UCSRA & (1<<RXC) == 0);
data = UDR;
Next, you have a block which looks like you meant to be part of a while loop, but it isn't. The body of the loop is the single statement abbove it. The block gets executed every time.
{
if(data=0x0a)
{
olddata=data;
movservo0(90,7); //move servo to certain degree
}
}
Another error is the condition in the if statement. It looks like you are trying to test if data is 0x0A, but that is not what is happening. Instead, you set data to be 0x0A, and then execute the inner part every time. The condition you probably want is if(data == 0x0A). Note the == instead of =.
So your code is equivalent to
while(1)
{
while(ucsra & (1<<RXC)) data=udr; // maybe read UDR into data
data=0x0a; // set data anyway
olddata=data;
movservo0(90,7); //move servo to certain degree
}
Again, for the jumping servo, I suspect some code that is omitted here that is also runs every time. Or else, the moveservo() function has a problem itself.
Related
I am working on a 2-axis CNC machine using an STM32F103C8T6 and using the HAL libraries. I've setup a seperate timer for each axis of the machine and have those configured in PWM mode.
I have a function called step_x(numberSteps, Direction) which takes in two parameters which are the number of steps to make and the direction to move in. The function sets the number of steps as the target number of steps in a global variable, sets the direction via GPIO write and then starts the PWM in interrupt mode using the HAL library:
void step_x(uint32_t numberSteps, uint16_t direction){
RELEASE_X=0;
steps_x_target = numberSteps;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, direction_x);
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
}
This then starts the PWM and I am counting the number of pulses via the timer update callback function:
void TIM1_UP_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE))
{
if (__HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE))
{
step_update('X');
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_UPDATE);
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1 );
}
}
}
Inside this callback, step_update() is called taking as a parameter which axis I am working with.
The step_update function adds +1 to a count for the number of steps that have occured and stops the PWM when the number of steps is equal to the target number of steps that was set. It also calls a function which keeps track of the position in mm rather than steps. (Y and Z axis cases removed for the sake of brevity)
void step_update(char axis){
switch(axis){
case 'X':
steps_x++;
updatePosition(axis);
if(steps_x==(2*steps_x_target)){ //check if 2* because the update event happens twice every pulse
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
steps_x_target=0;
steps_x=0;
RELEASE_X=1;
if(limitSwitchX_Trigger==1){
positionX=0;
limitSwitchX_Trigger=0;
NVIC_EnableIRQ(EXTI0_IRQn);
}
}
break;
case 'Y':
break;
case 'Z':
break;
}
}
I'm sure this is not an entirely efficient way to do this however it works well enough except for the fact that I have no way to call the step_x() function and wait for it to finish before making the call to the next one. I added the volatile variables RELEASE_X which is set to 0 when step_x() is called and set to 1 when the step_update() function has stopped the PWM when the target steps are reached. I thought using this that I may be able to do something like this which I would expect to step 800 pulses in one direction and then step 800 pulses in another direction:
step_x(800,0);
while(RELEASE_X!=1);
step_x(800,1);
However what happens is that the while loop ends up blocking the Timer1_Update callback from occuring and the pulses don't get counted. I expected that because the pulse counting is done in an ISR callback that the MCU would just jump to the ISR from this while loop and update the steps until RELEASE_X is set to true and then advance to the next call of step_x()? Why is this not so?
Could someone suggest a way that I can write code which will allow me to call a function which steps a certain amount of steps while waiting for them to finish before moving on to the next call? I am trying to implement Bresenhams line algorithm next and so I need to step a certain amount of steps and then only return from the call and advance to the next line of code when the steps are complete. (Essentially, how can I make this function blocking but without toggling GPIO pins/bit bashing)
https://github.com/Blargian/EPR400
It's not really an answer as to why this happened but I solved the problem by disabling the timer update and global interrupts in CubeMX under the NVIC tab. I removed the callback functions from my main.h and main.c and then I modified the step_x function to be:
void step_x(uint32_t numberSteps, uint16_t direction){
RELEASE_X=0;
steps_x_target = numberSteps;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, direction_x);
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
while(RELEASE_X!=1){
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE))
{
if (__HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE))
{
step_update('X');
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_UPDATE);
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1 );
}
}
}
}
Basically just moved the code that was in the callback function to within the while loop in the step_x function. The function is now a blocking function which is atually what I need anyway.
I'm trying to detect rising and falling temperatures using PIC16F877A MCU and two DS8B20 sensors. I'm facing with problems when I try to detect temperature falling. Here is my code what am I trying to do:
#include "main.h"
void main() {
//Turn on LCD backlight
output_high(PIN_D7);
// Initialize LCD module
lcd_init();
float Threshold_Value = 30; // Temperature threshold value
while (TRUE) {
Show_User_Info();
delay_ms(10);
Read_Sensors();
// Starting to read user button values
User_Buttons();
delay_ms(20); // Minimum amount of time to read user button values
// Starting to compare user set temperature value and upper sensor temperature read value.
Compare_Upper_Temp();
delay_ms(20);
//================================
// Checking, if the MCU pin connected to pump is high. If yes - do the waiting 'animation'
if (input(PIN_B5)) {
while(temp > Threshold_Value);
{
Bottom_Waiting_Animation();
}
// Experimenting....
// break;
// continue;
}
if (input(PIN_B5)) {
while(temp < Threshold_Value);
{
Bottom_Waiting_Animation();
}
// break;
}
// If the set temp is less than threshold - turn the pump off.
if (temp < Threshold_Value) {
input(PIN_B5) == 0;
}
}
}
When the pump is switched on, I need to wait until second sensor reaches threshold value (30C), after that I need to 'detect' when that temperature starts to drop from that 30C. This code which I uploaded 'works' only with one While(temp > Threshold_Value) loop. But when I insert the next one under it while(temp < Threshold_Value), MCU jumps in undefined area and gets stuck. This task sounds pretty easy, but I tried lots of different ways to solve this problem. Maybe one of the problem reasons could be multiple while loops?
Don't use a semicolon after the while condition.
Replace
while (condition);
{
... looped code ...
}
with
while (condition)
{
.... looped code ...
}
This is one reason I like to put open braces at the end of the condition (as you do in your if statements): it helps to see the obnoxious accidental semicolon.
I am currently trying to figure out a configuration in controlling servos connected to Arduinos using Nodebot johnny-five.io hosted on an RPi. My main goal is to make a hexapod from scratch; I don't like the idea of kits because it's all cookie cutter code and parts that you put together and it's more or less a remote controlled car where you didn't learn anything.
I just learned the basics about servos (which I'm selecting servos over stepper motors). And unfortunately, as a default, servo speed cant be controlled via PWM, only position. So the way around this is to create a loop that increments the servo 1 degree (or more) at a time with an X ms delay in the loop until the servo has reached the desired position. Now, this is fine and all if you're only controlling one servo at a time or X amount of servos at a time for moving to one set position to another. But I'm shooting for a fluid motion here; I want one leg to start moving before another leg has stopped. True fluidity in motion, to accomplish this, I would need an infinite loop that would check on input states set by control commands that the API would receive.
The problem here is that while loops are not asynchronous. So, I need to find a way to kick a loop off that sets the different servos at different speed ranges and different positions, and at the end of the loop checks for new input state updates. And I need to do this without creating a memory leak.
One way would be to create a set of dependency scripts that worked asynchronously for each of the servos (3 servos per leg, 6 legs, 18 servos thus 18 mini dependencies), but I'm not sure if that would be too much overhead or put much strain onto the RPi.
Am I overthinking this?
You could create a simple servo class and give each instance its own speed and starting position using an 'update' method. Use a longer delay to have the servo move slower. In the main loop you can continuously check for some input, tell the servos to move if necessary, using the update method.
#include <Servo.h>
class HexapodLegServo
{
Servo servo; // Servo instance
int pos; // Position/angle of the servo
int delay_millis; // 'Delay' between each update
long prev_millis;
int degree_change; // Angle increase each update
int start_pos; // Position to start at
int pin; // Pin servo is connected to
public:
HexapodLegServo (int whichPin, int delayMillis=15, int startPos=0)
{
pin = whichPin;
delay_millis = delayMillis;
start_pos = startPos;
degree_change = 1;
}
void attachToPin()
{
servo.attach(pin);
setStartPos();
}
void setStartPos() // Set initial position of the servo
{
servo.write(start_pos);
pos = start_pos;
}
void update() // Servo sweeps from end to end, and back
{
if (millis()-prev_millis > delay_millis)
{
prev_millis = millis();
servo.write(pos);
pos += degree_change;
if ((pos <= 0) || (pos >= 180))
{
degree_change *= -1; // Start moving in the reverse direction
}
}
}
};
// Main script
const int BUTTON = 4; // Button on pin 4
HexapodLegServo right_leg(9);
HexapodLegServo left_leg(10, 30, 90);
void setup()
{
Serial.begin(9600);
pinMode(BUTTON, INPUT_PULLUP); // Using a button to tell servos when to move
right_leg.attachToPin();
left_leg.attachToPin();
}
void loop()
{
if (digitalRead(BUTTON) == LOW) // If button is pushed (can be any type of input)
{ // update the position of the servos continuously
right_leg.update();
left_leg.update();
}
}
I currently have something close to the following implementation of a FPS independent game loop for physics based games. It works very well on just about every computer I have tested it on, keeping the game speed consistent when frame rate drops. However I am going to be porting to embedded devices which will likely struggle harder with video and I am wondering if it will still cut the mustard.
edits:
For this question assume that msecs() returns the time passed in milliseconds which the program has run. The implementation of msecs is different on different platforms. This loop is also run in different ways on different platforms.
#define MSECS_PER_STEP 20
int stepCount, stepSize; // these are not globals in the real source
void loop() {
int i,j;
int iterations =0;
static int accumulator; // the accumulator holds extra msecs
static int lastMsec;
int deltatime = msec() - lastMsec;
lastMsec = msec();
// deltatime should be the time since the last call to loop
if (deltatime != 0) {
// iterations determines the number of steps which are needed
iterations = deltatime/MSECS_PER_STEP;
// save any left over millisecs in the accumulator
accumulator += deltatime%MSECS_PER_STEP;
}
// when the accumulator has gained enough msecs for a step...
while (accumulator >= MSECS_PER_STEP) {
iterations++;
accumulator -= MSECS_PER_STEP;
}
handleInput(); // gathers user input from an event queue
for (j=0; j<iterations; j++) {
// here step count is a way of taking a more granular step
// without effecting the overall speed of the simulation (step size)
for (i=0; i<stepCount; i++) {
doStep(stepSize/(float) stepCount); // forwards the sim
}
}
}
I just have a few comments. The first is that you don't have enough comments. There are places where it's not clear what you are trying to do so it is difficult to say if there is a better way to do it, but I'll point those out as I come to them. First, though:
#define MSECS_PER_STEP 20
int stepCount, stepSize; // these are not globals in the real source
void loop() {
int i,j;
int iterations =0;
static int accumulator; // the accumulator holds extra msecs
static int lastMsec;
These are not initialized to anything. The probably turn up as 0, but you should have initialized them. Also, rather than declaring them as static you might want to consider putting them in a structure that you pass into loop by reference.
int deltatime = msec() - lastMsec;
Since lastMsec wasn't (initialized and is probably 0) this probably starts out as a big delta.
lastMsec = msec();
This line, just like the last line, calls msec. This is probably meant as "the current time", and these calls are close enough that the returned value is probably the same for both calls, which is probably also what you expected, but still, you call the function twice. You should change these lines to int now = msec(); int deltatime = now - lastMsec; lastMsec = now; to avoid calling this function twice. Current time getting functions often have much higher overhead than you think.
if (deltatime != 0) {
iterations = deltatime/MSECS_PER_STEP;
accumulator += deltatime%MSECS_PER_STEP;
}
You should have a comment here that says what this does, as well as a comment above
that says what the variables were meant to mean.
while (accumulator >= MSECS_PER_STEP) {
iterations++;
accumulator -= MSECS_PER_STEP;
}
This loop needs a comment. It also needs to not be there. It appears that it could have been replaced with iterations += accumulator/MSECS_PER_STEP; accumulator %= MSECS_PER_STEP;. The division and modulus should run in shorter and more consistent time than the loop on any machine that has hardware division (which many do).
handleInput(); // gathers user input from an event queue
for (j=0; j<iterations; j++) {
for (i=0; i<stepCount; i++) {
doStep(stepSize/(float) stepCount); // forwards the sim
}
}
Doing steps in a loop independent of input will have the effect of making the game unresponsive if it does execute slow and get behind. It appears, at least, that if the game gets behind all of the input will start to stack up and get executed together and all of the in-game time will pass in one chunk. This is a less than graceful way to fail.
Additionally, I can guess what the j loop (outer loop) means, but the inner loop I am less clear on. also, the value passed to the doStep function -- what does that mean.
}
This is the last curly brace. I think that it looks lonely.
I don't know what goes on as far as whatever calls your loop function, which may be out of your control, and that may dictate what this function does and how it looks, but if not I hope that you will reconsider the structure. I believe that a better way to do it would be to have a function that is called repeatedly but with only one event at the time (issued regularly at a relatively short period). These events can be either user input events or timer events. User input events just set things up to react upon the next timer event. (when you don't have any events to process you sleep)
You should always assume that each timer event is processed at the same period, even though there may be some drift here if the processing gets behind. The main oddity that you may notice here is that if the game gets behind on processing timer events and then catches up again the time within the game may appear to slow down (below real time), then speed up (to real time), and then slow back down (to real time).
Ways to deal with this include only allowing one timer event to be in the event queue at one time, which would result in time appearing to slow down (below real time) and then speed back up (to real time) with no super speed interval.
Another way to do this, which is functionally similar to what you have, would be to have the last step of processing each timer event be to queue up the next timer event (note that no one else should send timer events {except for the first one} if this is the way you choose to implement the game). This would mean doing away with the regular time intervals between timer events and also restrict the ability for the program to sleep, since at the very least every time the event queue were inspected there would be a timer event to process.
I think I might be having a stack overflow problem or something similar in my embedded firmware code. I am a new programmer and have never dealt with a SO so I'm not sure if that is what's happening or not.
The firmware controls a device with a wheel that has magnets evenly spaced around it and the board has a hall effect sensor that senses when magnet is over it. My firmware operates the stepper and also count steps while monitoring the magnet sensor in order to detect if the wheel has stalled.
I am using a timer interrupt on my chip (8 bit, 8057 acrh.) to set output ports to control the motor and for the stall detection. The stall detection code looks like this...
// Enter ISR
// Change the ports to the appropriate value for the next step
// ...
StallDetector++; // Increment the stall detector
if(PosSensor != LastPosMagState)
{
StallDetector = 0;
LastPosMagState = PosSensor;
}
else
{
if (PosSensor == ON)
{
if (StallDetector > (MagnetSize + 10))
{
HandleStallEvent();
}
}
else if (PosSensor == OFF)
{
if (StallDetector > (GapSize + 10))
{
HandleStallEvent();
}
}
}
this code is called every time the ISR is triggered. PosSensor is the magnet sensor. MagnetSize is the number of stepper steps that it takes to get through the magnet field. GapSize is the number of steps between two magnets. So I want to detect if the wheel gets stuck either with the sensor over a magnet or not over a magnet.
This works great for a long time but then after a while the first stall event will occur because 'StallDetector > (MagnetSize + 10)' but when I look at the value of StallDetector it is always around 220! This doesn't make sense because MagnetSize is always around 35. So the stall event should have been triggered at like 46 but somehow it got all the way up to 220? And I don't set the value of stall detector anywhere else in my code.
Do you have any advice on how I can track down the root of this problem?
The ISR looks like this
void Timer3_ISR(void) interrupt 14
{
OperateStepper(); // This is the function shown above
TMR3CN &= ~0x80; // Clear Timer3 interrupt flag
}
HandleStallEvent just sets a few variable back to their default values so that it can attempt another move...
#pragma save
#pragma nooverlay
void HandleStallEvent()
{
///*
PulseMotor = 0; //Stop the wheel from moving
SetMotorPower(0); //Set motor power low
MotorSpeed = LOW_SPEED;
SetSpeedHz();
ERROR_STATE = 2;
DEVICE_IS_HOMED = FALSE;
DEVICE_IS_HOMING = FALSE;
DEVICE_IS_MOVING = FALSE;
HOMING_STATE = 0;
MOVING_STATE = 0;
CURRENT_POSITION = 0;
StallDetector = 0;
return;
//*/
}
#pragma restore
Is PosSensor volatile? That is, do you update PosSensor somewhere, or is it directly reading a GPIO?
I assume GapSize is rather large (> 220?) It sounds to me like you might have a race condition.
// PosSensor == OFF, LastPosMagState == OFF
if(PosSensor != LastPosMagState)
{
StallDetector = 0;
LastPosMagState = PosSensor;
}
else
{
// Race Condition: PosSensor turns ON here
// while LastPosMagState still == OFF
if (PosSensor == ON)
{
if (StallDetector > (MagnetSize + 10))
{
HandleStallEvent();
}
}
else if (PosSensor == OFF)
{
if (StallDetector > (GapSize + 10))
{
HandleStallEvent();
}
}
}
You should cache the value of PosSensor once, right after doing StallDetector++, so that in the event PosSensor changes during your code, you don't start testing the new value.
This is definitely not stack overflow. If you blew the stack (overflowed it) your application would simply crash. This sounds more like something we used to call memory stomping in my C++ days. You may not be accessing the memory location that the StallDetector value occupies via StallDetector variable alone. There may be another part of your code "stomping" this particular memory location erroneously.
Unfortunately, this kind of issue is very hard to track down. About the only thing you could do is systematically isolate (remove from execution) chunks of your code until you narrow down and find the bug.
Do you have nest ISRs on your system? Could be something along the lines of start your ISR and increment your count, then interrupt it and do it again. Do this enough times and your interrupt stack can overflow. It could also explain such a high counter variable as well.
Does HandleStallEvent() "look at" StallDetector within the ISR or does it trigger something on the main loop? If it's on the main loop, are you clearing the interrupt bit?
Or are you looking at StallDetector from a debugger outside the ISR? Then a retriggered interrupt would use the correct value each time, but execute too many times, and you would only see the final, inflated value.
On second thought, more likely you don't have to clear an interrupt-generating register, but rather the interrupt pin is remaining asserted by the sensor. You need to ignore the interrupt after it's first handled until the line deasserts, such as by having the original ISR disable itself and and reinstall it in a second ISR which handles the 1->0 transition.
You might then also need to add debouncing hardware or adjust it if you have it.
Check your parameter types. If you defined the parameters in a way different than the caller expects then calling your method could overwrite the space that variable is stored in. (For instance if you wrote the function expecting an int but it is pushing a long onto the stack.)
You could see what additional options your debugger supports. In Visual Studio, for example, it is possible to set a "data breakpoint", where you break when a memory location changes (or is set to a certain value, or above a threshold, ...).
If something like this is possible in your case, you could see where the data is changed and if there is someone else writing to the memory erroneously.