RPI Drive servo by PWM (wiringpi / C programming) - c

I trie to drive a servo with the Raspberry PI using the PWM on GPIO Pin 18 i wired the setup like you can see below.
When i drive the servo i can do this without any problems the commands that i use you can see below.
gpio -g mode 18 pwm
gpio pwm-ms
gpio pwmc 192
gpio pwmr 2000
gpio -g pwm 18 150
gpio -g pwm 18 200
That works fine, to go to the position without any problem but when i try to do the same with a C program using wiringpi like you can see below.
#include <wiringPi.h>
#include <stdio.h>
int main (void)
{
printf ("Raspberry Pi wiringPi test program\n");
wiringPiSetupGpio();
pinMode (18, PWM_OUTPUT) ;
pwmSetMode (PWM_MODE_MS);
pwmSetRange (2000);
pwmSetClock (192);
pwmWrite(18,150);
delay(1000);
pwmWrite(18,200);
return 0;
}
The program and the raspberry pi chrash so i have to reboot them does anybody know what i do wrong and how i can solve the problem it is very frustrating?

I spent weeks on controlling two servo (SG90) using WiringPi and programming in C, there're three things that I recommend.
1.Using BCM GPIO instead of WiringPi Pin because controlling more than one servo, you might need more than one pin such like 1(WiringPi Pin)/18(BCM GPIO) for another servo, For RPi3 B+ version, it give access to two channels for hardware PWM. Channel 0 on gpios 12/18 and channel 1 on gpios 13/19, it's easy and no need to worry about pin mapping exists if you adpopt BCM GPIO.
2.Better make sure there is only one program access PWM. pins at one time. Based on my experience, if you find that using command like "gpio -g pwm 18 25" is workable but otherwise using code like "pwmWrite(18, 25)" doesn's get any servo responds, maybe try "ps -A" to make sure if any other program is racing the access of your servo.
3.The last and the hardest one for me, when I execute pwmWrite(18, 25)" on PWM. pin 18 triggers the same instruction onto PWM. pin 12, which means pwmWrite(18, 25) triggers pwmWrite(12, 25). To solve this situation, changing the modes of other pins of servos which should freeze without any moving to be input mode and set all of them to be pull-down.
For details, codes for controlling two servos with PWM. Channel 0 on gpios 12/18.
Basic function:
void servo_init() {
servo_open(0);
delay(DELAY_SERVO);
servo_open(1);}
and
void servo_open(int servo) {
switch (servo) {
case 0:
pullUpDnControl(SERVO_0, PUD_OFF);
pinMode(SERVO_0, PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);
pwmSetClock(PWM_CHANNEL_0_CLOCK);
pwmSetRange(PWM_CHANNEL_0_RANGE);
break;
case 1:
pullUpDnControl(SERVO_1, PUD_OFF);
pinMode(SERVO_1, PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);
pwmSetClock(PWM_CHANNEL_0_CLOCK);
pwmSetRange(PWM_CHANNEL_0_RANGE);
break;
default:
break;
}}
and
void servo_close(int servo) {
switch (servo) {
case 0:
pinMode(SERVO_0, INPUT);
pullUpDnControl(SERVO_0, PUD_DOWN);
break;
case 1:
pinMode(SERVO_1, INPUT);
pullUpDnControl(SERVO_1, PUD_DOWN);
break;
default:
break;
}}
and
void servo(int servo, int angle) {
switch (servo) {
case 0:
servo = SERVO_0;
break;
case 1:
servo = SERVO_1;
break;
default:
servo = -1;
break;
}
switch (angle) {
case 90:
value = 25;
break;
case -90:
value = 10;
break;
case 0:
value = 14;
break;
default:
break;
}
if (servo == -1) return;
pwmWrite(servo, value);}
Rotate one servo connected to 18 (BCM GPIO)
Close others before you are going to rotate one
servo_close(1);
delay(DELAY_SERVO);
Rotate
servo(0, 90);
delay(3*DELAY_MAGIC);
servo(0, 0);
Reset all of servos to their init angles for fixing servo occasional jitter
delay(DELAY_SERVO);
servo_init();
Check more source code and informations about servo and sensor on Raspberry: MY GitHub

Try "sudo ./servo"
Hope it will work.

Related

Raspberry Pi 3 PWM Led Pulse

I want to control LED diod with PWM using bcm2835.h and pure C langueage. My code does not work. What am I missing?
I have tried "gpio" console command and it works fine, so I know that led is connected to the right ports. I can turn it on using console command:
gpio pwm 1 1024
My code:
#include <bcm2835.h>
#include <stdio.h>
// PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18) in alt fun 5.
// Note that this is the _only_ PWM pin available on the RPi IO headers
#define PIN RPI_GPIO_P1_12
// and it is controlled by PWM channel 0
#define PWM_CHANNEL 0
// This controls the max range of the PWM signal
#define RANGE 1024
int main(int argc, char **argv)
{
if (!bcm2835_init())
{
return 1;
}
// Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5);
// Clock divider is set to 16.
// With a divider of 16 and a RANGE of 1024, in MARKSPACE mode,
// the pulse repetition frequency will be
// 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM
bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16);
bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1);
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE);
while(1)
{
bcm2835_pwm_set_data(PWM_CHANNEL, 1024);
bcm2835_delay(10);
}
bcm2835_close();
return 0;
}
I expect that my LED will turn on.
This is stupid, but after checking the math, code, wiring I discovered that app needs to be run with root privileges to have on-board access to the pins. It works fine. Topic can be closed.

Why does my pin interupt works only once through out the process?

I have to authenticate a transaction, say a system which will use a pre-fed authentication id to verify any user using the system. The authentication id is supposed to be changed by a super-user using communication through Serial Protocol. Each time a transaction gets completed user has to press a push button to officially finish the transaction and enable super user to feed another authentication ID.
I am able to change the authentication id using Serial event interupt in Arduino, but my pin change interupt is working only once, so I cannot finish the 2nd transaction.
I tried it without using pin change interupt also but, that made a lot of mess in my code and did not work properly as i wanted, maybe some-thing or some logic I am not able to apply correctly.
```Arduino C language`````
void setup()
{
pinMode(44, OUTPUT);
pinMode(45, OUTPUT);
pinMode(46, OUTPUT);
Serial.begin(9600);
//gsm_port.begin(9600);
// Turn on the transmission, reception, and Receive interrupt
Serial1.begin(9600);
attachInterrupt(0, pin_ISR, RISING); //0 here defines pin 2 of Mega2560
}
void pin_ISR() //ISR for when box is manually closed a latch gets closed and high value is recvd on pin 2(only pins 2,3 are GPIO interupt pin of Mega2560)//
{
b1 = digitalRead(2);
if(b1==HIGH)
{
digitalWrite(44, LOW);
digitalWrite(45, LOW);
digitalWrite(46, LOW);
memset(&fed_id[0], 1, sizeof(fed_id)); //clearing fed_id so that once used cannot be used again till new id is feeded through serial event
}
}
void serialEvent1() //Serial Rx ISR for feeding new fed_id
{
while (Serial1.available())
{
rec = Serial1.read();
a[i] = rec;
i++
}
}
void loop()
{
char key = keypad.getKey();
if (key)
{
///.....some operation here......///
switch(key)
{ //try implementing shelf not oprning feature if occupied here with each case using 3 IR sensors.
case '1': digitalWrite(44, HIGH);
break;
case '2': digitalWrite(45, HIGH);
break;
case '3': digitalWrite(46, HIGH);
break;
}
}
}//closing for if(key)
}//closing for void loop()
If the above is possible without using interupts then too i would love to have a soultion. Please help me to understand why this is not going the right way and also help me finding a solution
There was no problem with the code actually and what was discussed in comments that we need to set and reset the interrupt flags/pins, is not the case with Arduino, Arduino does it automatically, while in many controllers we do need to do those things, however the problem here was with the hardware and not any part of code. Just a resistor was creating this problem on Proteus Simulation, however on actual hardware it worked completely fine.

Arduino won't recognise a 5v input

I am very new to programming. I am writing a program, for an Arduino clone. I have a 12V coil relay, that works off an 12V IR switch. The relay has picked up 5V from the Arduino, and will supply 5V to pin 1, when the relay is switched EG something moving in front of the IR switch.
The program seems to ignore the incoming 5V, and continues the program as though it wasn't even trying to read it.
When I check on the serial monitor, what the pin is reading (high or low), it just shows "xxx" when there is nothing present, and doesn't react when my hand signals the switch.
I am sure it is some basic C++ code syntax error.
Code below:
void loop() {
analogWrite(channel_a_enable, 255);
//turns feeder motor on through H bridge, to feed brass case
digitalWrite(channel_a_input_1, HIGH);
digitalWrite(channel_a_input_2, LOW);
val = digitalRead (sensor_ir_pin);
//reads IR switch and checks if it has a case present yet
Serial.println(val);
if (val = HIGH)
//if brass case rolls past sensor, switching IR switch and relay
analogWrite(channel_a_enable, 0);
//turns feeder motor off
digitalWrite(channel_a_input_1, LOW);
digitalWrite(channel_a_input_2, LOW);
current_potent = analogRead(A0);
//reads the potentiometer setting (set for a max of 15 seconds time)
delay(current_potent * 14.6627);
//delays, while the brass case is in the flame, getting annealed. Also provides the multiplier for 15000 mill seconds into 1023 read point on the potentiometer

Program Working on Old Device and New Device's Simulator but not on New Device

I'm hitting a roadblock in porting over a program I previously wrote for the PIC10F200 (see this related SO question). Turns out another component on the board needed to be swapped out for something that needed to be communicated with through I2C, so ergo, I'm porting the program to the PIC12LF1552.
This is how the program currently works (at least on the PIC10F200)
Program starts at IDLE (no lights on)
Press the button, the T0CKI pin (in the PIC12LF1552's case, RA2) is already pulled up to VDD (~3.3V) by an external pull-up resistor, the button is connected to ground and the pin, ergo pulling T0CKI's signal to LO.
TMR0 increments (supposedly)
After a time period where PORTAbits.RA2 settles, state increments
switch block moves to turn the external LED on, in the previous version of the circuit, this would also activate the IC this pin is connected to.
Rinse repeat for the other 3 states.
I have re-verified this functionality through using MPLAB X's simulator where I fired T0CKI (again, configured as RA2, again confirmed by the simulator) to HI and then to LO to engage the TMR0 code. state increments, and everybody is happy.
When I program the device using either MPLAB X connected to my PICkit3 or the included standalone programmer MPLAB IPE, the program does not work as intended. I have re-verified all connections, the programming port is connected as it should be. The button is attached the right pin. The test LED is attached to the right pin. For the time being we are not considering any I2C communication, I just want to see my status LED (RA4) toggle.
I know that now that I've transitioned to a midrange PIC, I can use the interrupt features, but for the time being I want to get what I know has worked on a much simpler device working on the current one.
My question then is, why doesn't this program work when programmed to the PIC12LF1552, but yet works on the PIC12LF1552 simulator AND its previous incarnation worked on the PIC10F200 (both programmed and simulated)?
Thanks in advance everyone!
The following is the entire program:
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#endif
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include <stdio.h>
#include <stdlib.h>
/******************************************************************************/
/* Defines */
/******************************************************************************/
//#define SYS_FREQ 16000000L
//#define FCY SYS_FREQ/4
#define _XTAL_FREQ 500000
__CONFIG
(
MCLRE_ON &
CP_OFF &
BOREN_OFF &
WDTE_OFF &
PWRTE_OFF &
FOSC_INTOSC
);
void main(void)
{
TRISA = 0b101111;
OPTION_REG = 0b01111111;
APFCONbits.SDSEL = 1;
unsigned char state = 0;
unsigned char count = 0;
while(1)
{
switch (state)
{
case 0: // IDLE/OFF
if (LATAbits.LATA4) LATAbits.LATA4 = 0;
break;
case 1: // ON
if (!LATAbits.LATA4) LATAbits.LATA4 = 1;
break;
case 2: // BLINK (slow)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(100);
break;
case 3: // BLINK (fast)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(50);
break;
case 4: // BEAT DETECT
LATAbits.LATA4 = LATAbits.LATA5;
break;
default:
state = 0;
break;
}
if (TMR0 > 0)
{
while (count < 20)
{
if (!PORTAbits.RA2) count = 0;
__delay_ms(10);
count++;
}
TMR0 = 0;
state++;
}
}
}
Some of the pins may be configured as Analog Inputs.
From the Datasheet for this device
"The operation of pin RA4 as analog is selected by setting the ANS3
bit in the ANSEL register which is the default set-ting after a
Power-on Reset".
If you do not set the ANSEL register the pin cannot be used as output as it is configured as an analog input.
This applies to all the pins that can be A/D inputs.
I do not see any configuration bit setup in your code.
Setting ANSEL and ANSELH to 0 should do the trick.
According to the this documentation , on page 93 about the ANSELA register
"The ANSELA bits default to the Analog mode after Reset. To use any
pins as digital general purpose or peripheral inputs, the
corresponding ANSEL bits must be initialized to ‘0’ by user software."
If you don't plan to use analog inputs, you may add something like ANSELA=0;

Raspberry Pi | Linux | Detection of releasing a key | WASD keyboard control in C

I would like to implement a WASD control in my PI. This also works quite well so far.
#include "bcm2835.h"
#define SLEEPTIME 500
#define GPIO17 RPI_GPIO_P1_11
...
while(running) {
// get key
printf("wait for key:");
system("/bin/stty raw");
key = getchar();
system("/bin/stty cooked");
printf(" key %i pressed!\n", key);
// key-logic
switch(key) {
case 'w':
printf("set GPIO 17 HIGH");
bcm2835_gpio_write(GPIO17, HIGH);
bcm2835_delay(SLEEPTIME); // <-- wanna remove this!
break;
}
// reset GPIO
bcm2835_gpio_write(GPIO17, LOW);
printf("\n");
}
...
In my current implementation I have the following problem:
If I press the W key so it will be detected and sets the GPIO. After a short delay the GPIO is reset and it wait for the next key.
I want, however, that the GPIO is set as long as the W button is pressed. Do you have a hint on how I can achieve this? Is it a option that to detect a release of a key?
I have already thought of Interruputs but not found a suitable solution.
Thank you!
EDIT1:
I have found a solution that works great. Many thanks to Loki Software, Inc.
with John R. Hall.
Here you can get it: keycodes.c
and here the detailed instructions: Programming Linux Games
EDIT2:
I have to unfortunately withdraw my statement.
The program works under debian on a notebook. On the Rasbian with usb keyboard it will not work optimally.
While it starts without error but does not respond to the release of a key.
Does anyone know any advice?

Resources