Servo driver to drive an Arm. Some fixes needed for threads
This commit is contained in:
parent
5076ec7446
commit
652f24532a
152
src/drivers/servo.cpp
Normal file
152
src/drivers/servo.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#include "src/drivers/Servo.h"
|
||||
|
||||
#include "mbed-os/rtos/Thread.h"
|
||||
|
||||
namespace drivers {
|
||||
|
||||
namespace {
|
||||
|
||||
Thread* pServoThread;
|
||||
|
||||
double posToPulseWidthInUs(double position)
|
||||
{
|
||||
return (position/2+1.5)*1000;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
double from;
|
||||
double to;
|
||||
double intervalInSec;
|
||||
PwmOut* pServo;
|
||||
} SweepData;
|
||||
|
||||
typedef struct {
|
||||
double latestPosition;
|
||||
PwmOut* pServo;
|
||||
} NodData;
|
||||
|
||||
void sweepWorker(SweepData* pSweepData)
|
||||
{
|
||||
SweepData sweepData = *pSweepData;
|
||||
|
||||
double resolution(24);
|
||||
double range(sweepData.to - sweepData.from);
|
||||
double value(sweepData.to);
|
||||
double increment(range/resolution);
|
||||
|
||||
while (true)
|
||||
{
|
||||
value += increment;
|
||||
|
||||
if (value >= sweepData.to)
|
||||
{
|
||||
increment = -abs(increment);
|
||||
}
|
||||
else if (value <= sweepData.from)
|
||||
{
|
||||
increment = abs(increment);
|
||||
}
|
||||
sweepData.pServo->pulsewidth_us(posToPulseWidthInUs(value));
|
||||
|
||||
// E.g resolution 10 will give a 100ms delay between steps
|
||||
Thread::wait(1000/resolution);
|
||||
}
|
||||
}
|
||||
|
||||
void nodWorker(NodData* pNodData)
|
||||
{
|
||||
pNodData->pServo->pulsewidth_us(posToPulseWidthInUs(pNodData->latestPosition-0.4));
|
||||
Thread::wait(500);
|
||||
pNodData->pServo->pulsewidth_us(posToPulseWidthInUs(pNodData->latestPosition));
|
||||
}
|
||||
}
|
||||
|
||||
Servo::Servo(PinName servoArm)
|
||||
: m_servo(servoArm)
|
||||
, m_dir(1)
|
||||
, m_inMovement(false)
|
||||
, m_latestPosition(0.0)
|
||||
{
|
||||
center();
|
||||
}
|
||||
|
||||
void Servo::center()
|
||||
{
|
||||
//stop();
|
||||
|
||||
setPosition(0.0);
|
||||
}
|
||||
|
||||
void Servo::resetTimers()
|
||||
{
|
||||
m_servo.period_ms(20);
|
||||
}
|
||||
|
||||
void Servo::setPosition(double position)
|
||||
{
|
||||
/* TODO: For now we need to call "stop()"
|
||||
before setting pos when we know we've ran a thread before
|
||||
Stop does not work here for some reason */
|
||||
//stop();
|
||||
|
||||
double increment = position*500.0;
|
||||
|
||||
if (increment < -500)
|
||||
{
|
||||
increment = -500;
|
||||
}
|
||||
else if (increment > 500)
|
||||
{
|
||||
increment = 500;
|
||||
}
|
||||
|
||||
m_servo.pulsewidth_us(1500 + increment*(double)m_dir);
|
||||
|
||||
m_latestPosition = position;
|
||||
}
|
||||
|
||||
void Servo::invert()
|
||||
{
|
||||
m_dir = -1;
|
||||
}
|
||||
|
||||
void Servo::sweep(double from, double to, double intervalInSec)
|
||||
{
|
||||
pServoThread = new Thread;
|
||||
|
||||
SweepData sweepData;
|
||||
sweepData.from = from;
|
||||
sweepData.to = to;
|
||||
sweepData.intervalInSec = intervalInSec;
|
||||
sweepData.pServo = &m_servo;
|
||||
|
||||
pServoThread->start(callback(sweepWorker, &sweepData));
|
||||
wait(5); // Task will run for at least this long (can get destroyed after)
|
||||
}
|
||||
|
||||
void Servo::nod()
|
||||
{
|
||||
NodData nodData;
|
||||
nodData.pServo = &m_servo;
|
||||
nodData.latestPosition = m_latestPosition;
|
||||
|
||||
pServoThread = new Thread;
|
||||
|
||||
pServoThread->start(callback(nodWorker, &nodData));
|
||||
wait(1);
|
||||
pServoThread->join(); // Wait for the nod to end
|
||||
}
|
||||
|
||||
void Servo::stop()
|
||||
{
|
||||
if (pServoThread->get_state() != Thread::Deleted)
|
||||
{
|
||||
pServoThread->terminate();
|
||||
}
|
||||
if (pServoThread != NULL)
|
||||
{
|
||||
delete pServoThread;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace drivers
|
47
src/drivers/servo.h
Normal file
47
src/drivers/servo.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "mbed.h"
|
||||
|
||||
namespace drivers {
|
||||
|
||||
class Servo
|
||||
{
|
||||
public:
|
||||
|
||||
Servo(PinName servoArm);
|
||||
|
||||
void center();
|
||||
|
||||
//! Will set the reset the period and center the servo
|
||||
void resetTimers();
|
||||
|
||||
//! in range [-1,1]
|
||||
void setPosition(double position);
|
||||
|
||||
//! changes the direction of this arm
|
||||
void invert();
|
||||
|
||||
//! Will start sweeping the servo without end
|
||||
void sweep(double from, double to, double intervalInSec);
|
||||
|
||||
//! The servo will nod like a gentleman
|
||||
void nod();
|
||||
|
||||
//! Stops any active movement (Thread)
|
||||
void stop();
|
||||
|
||||
public:
|
||||
|
||||
PwmOut m_servo;
|
||||
|
||||
private:
|
||||
|
||||
int m_dir;
|
||||
|
||||
bool m_inMovement;
|
||||
|
||||
double m_latestPosition;
|
||||
|
||||
};
|
||||
|
||||
} // namespace drivers
|
Loading…
x
Reference in New Issue
Block a user